aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwmc3200wifi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi')
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c35
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c77
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h23
-rw-r--r--drivers/net/wireless/iwmc3200wifi/debugfs.c23
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.c50
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.h29
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h11
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c44
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c8
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c66
-rw-r--r--drivers/net/wireless/iwmc3200wifi/tx.c66
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h36
12 files changed, 428 insertions, 40 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 2e00a4b389e6..7c4f44a9c3e6 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -678,6 +678,9 @@ static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
678 case TX_POWER_AUTOMATIC: 678 case TX_POWER_AUTOMATIC:
679 return 0; 679 return 0;
680 case TX_POWER_FIXED: 680 case TX_POWER_FIXED:
681 if (!test_bit(IWM_STATUS_READY, &iwm->status))
682 return 0;
683
681 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 684 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
682 CFG_TX_PWR_LIMIT_USR, dbm * 2); 685 CFG_TX_PWR_LIMIT_USR, dbm * 2);
683 if (ret < 0) 686 if (ret < 0)
@@ -685,6 +688,7 @@ static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
685 688
686 return iwm_tx_power_trigger(iwm); 689 return iwm_tx_power_trigger(iwm);
687 default: 690 default:
691 IWM_ERR(iwm, "Unsupported power type: %d\n", type);
688 return -EOPNOTSUPP; 692 return -EOPNOTSUPP;
689 } 693 }
690 694
@@ -721,6 +725,33 @@ static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
721 CFG_POWER_INDEX, iwm->conf.power_index); 725 CFG_POWER_INDEX, iwm->conf.power_index);
722} 726}
723 727
728int iwm_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
729 struct cfg80211_pmksa *pmksa)
730{
731 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
732
733 return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_ADD);
734}
735
736int iwm_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
737 struct cfg80211_pmksa *pmksa)
738{
739 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
740
741 return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_DEL);
742}
743
744int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
745{
746 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
747 struct cfg80211_pmksa pmksa;
748
749 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
750
751 return iwm_send_pmkid_update(iwm, &pmksa, IWM_CMD_PMKID_FLUSH);
752}
753
754
724static struct cfg80211_ops iwm_cfg80211_ops = { 755static struct cfg80211_ops iwm_cfg80211_ops = {
725 .change_virtual_intf = iwm_cfg80211_change_iface, 756 .change_virtual_intf = iwm_cfg80211_change_iface,
726 .add_key = iwm_cfg80211_add_key, 757 .add_key = iwm_cfg80211_add_key,
@@ -737,6 +768,9 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
737 .set_tx_power = iwm_cfg80211_set_txpower, 768 .set_tx_power = iwm_cfg80211_set_txpower,
738 .get_tx_power = iwm_cfg80211_get_txpower, 769 .get_tx_power = iwm_cfg80211_get_txpower,
739 .set_power_mgmt = iwm_cfg80211_set_power_mgmt, 770 .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
771 .set_pmksa = iwm_cfg80211_set_pmksa,
772 .del_pmksa = iwm_cfg80211_del_pmksa,
773 .flush_pmksa = iwm_cfg80211_flush_pmksa,
740}; 774};
741 775
742static const u32 cipher_suites[] = { 776static const u32 cipher_suites[] = {
@@ -782,6 +816,7 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
782 816
783 set_wiphy_dev(wdev->wiphy, dev); 817 set_wiphy_dev(wdev->wiphy, dev);
784 wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX; 818 wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX;
819 wdev->wiphy->max_num_pmkids = UMAC_MAX_NUM_PMKIDS;
785 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 820 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
786 BIT(NL80211_IFTYPE_ADHOC); 821 BIT(NL80211_IFTYPE_ADHOC);
787 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz; 822 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 7e12438551ba..777584d76a88 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -99,6 +99,10 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
99 return ret; 99 return ret;
100} 100}
101 101
102static int modparam_wiwi = COEX_MODE_CM;
103module_param_named(wiwi, modparam_wiwi, int, 0644);
104MODULE_PARM_DESC(wiwi, "Wifi-WiMAX coexistence: 1=SA, 2=XOR, 3=CM (default)");
105
102static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = 106static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
103{ 107{
104 {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS}, 108 {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS},
@@ -122,18 +126,18 @@ static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
122static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = 126static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] =
123{ 127{
124 {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS}, 128 {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS},
125 {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, 129 {4, 4, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
126 {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, 130 {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
127 {5, 5, 0, COEX_CALIBRATION_FLAGS}, 131 {6, 6, 0, COEX_CALIBRATION_FLAGS},
128 {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, 132 {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
129 {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS}, 133 {6, 5, 0, COEX_CONNECTION_ESTAB_FLAGS},
130 {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, 134 {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
131 {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, 135 {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
132 {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, 136 {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS},
133 {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, 137 {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
134 {1, 1, 0, COEX_RF_ON_FLAGS}, 138 {1, 1, 0, COEX_RF_ON_FLAGS},
135 {1, 1, 0, COEX_RF_OFF_FLAGS}, 139 {1, 1, 0, COEX_RF_OFF_FLAGS},
136 {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, 140 {7, 7, 0, COEX_STAND_ALONE_DEBUG_FLAGS},
137 {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, 141 {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
138 {1, 1, 0, COEX_RSRVD1_FLAGS}, 142 {1, 1, 0, COEX_RSRVD1_FLAGS},
139 {1, 1, 0, COEX_RSRVD2_FLAGS} 143 {1, 1, 0, COEX_RSRVD2_FLAGS}
@@ -148,7 +152,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
148 152
149 coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK; 153 coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK;
150 154
151 switch (iwm->conf.coexist_mode) { 155 switch (modparam_wiwi) {
152 case COEX_MODE_XOR: 156 case COEX_MODE_XOR:
153 case COEX_MODE_CM: 157 case COEX_MODE_CM:
154 coex_enabled = 1; 158 coex_enabled = 1;
@@ -173,7 +177,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
173 COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK | 177 COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK |
174 COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK; 178 COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK;
175 179
176 switch (iwm->conf.coexist_mode) { 180 switch (modparam_wiwi) {
177 case COEX_MODE_XOR: 181 case COEX_MODE_XOR:
178 memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl, 182 memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl,
179 sizeof(iwm_sta_xor_prio_tbl)); 183 sizeof(iwm_sta_xor_prio_tbl));
@@ -184,7 +188,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
184 break; 188 break;
185 default: 189 default:
186 IWM_ERR(iwm, "Invalid coex_mode 0x%x\n", 190 IWM_ERR(iwm, "Invalid coex_mode 0x%x\n",
187 iwm->conf.coexist_mode); 191 modparam_wiwi);
188 break; 192 break;
189 } 193 }
190 } else 194 } else
@@ -192,7 +196,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
192 196
193 return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD, 197 return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD,
194 &coex_table_cmd, 198 &coex_table_cmd,
195 sizeof(struct iwm_coex_prio_table_cmd), 1); 199 sizeof(struct iwm_coex_prio_table_cmd), 0);
196} 200}
197 201
198int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) 202int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested)
@@ -396,7 +400,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags)
396 return ret; 400 return ret;
397 401
398 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 402 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
399 CFG_COEX_MODE, iwm->conf.coexist_mode); 403 CFG_COEX_MODE, modparam_wiwi);
400 if (ret < 0) 404 if (ret < 0)
401 return ret; 405 return ret;
402 406
@@ -929,3 +933,58 @@ int iwm_target_reset(struct iwm_priv *iwm)
929 933
930 return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); 934 return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
931} 935}
936
937int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
938 struct iwm_umac_notif_stop_resume_tx *ntf)
939{
940 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
941 struct iwm_umac_cmd umac_cmd;
942 struct iwm_umac_cmd_stop_resume_tx stp_res_cmd;
943 struct iwm_sta_info *sta_info;
944 u8 sta_id = STA_ID_N_COLOR_ID(ntf->sta_id);
945 int i;
946
947 sta_info = &iwm->sta_table[sta_id];
948 if (!sta_info->valid) {
949 IWM_ERR(iwm, "Invalid STA: %d\n", sta_id);
950 return -EINVAL;
951 }
952
953 umac_cmd.id = UMAC_CMD_OPCODE_STOP_RESUME_STA_TX;
954 umac_cmd.resp = 0;
955
956 stp_res_cmd.flags = ntf->flags;
957 stp_res_cmd.sta_id = ntf->sta_id;
958 stp_res_cmd.stop_resume_tid_msk = ntf->stop_resume_tid_msk;
959 for (i = 0; i < IWM_UMAC_TID_NR; i++)
960 stp_res_cmd.last_seq_num[i] =
961 sta_info->tid_info[i].last_seq_num;
962
963 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stp_res_cmd,
964 sizeof(struct iwm_umac_cmd_stop_resume_tx));
965
966}
967
968int iwm_send_pmkid_update(struct iwm_priv *iwm,
969 struct cfg80211_pmksa *pmksa, u32 command)
970{
971 struct iwm_umac_pmkid_update update;
972 int ret;
973
974 memset(&update, 0, sizeof(struct iwm_umac_pmkid_update));
975
976 update.command = cpu_to_le32(command);
977 if (pmksa->bssid)
978 memcpy(&update.bssid, pmksa->bssid, ETH_ALEN);
979 if (pmksa->pmkid)
980 memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
981
982 ret = iwm_send_wifi_if_cmd(iwm, &update,
983 sizeof(struct iwm_umac_pmkid_update), 0);
984 if (ret) {
985 IWM_ERR(iwm, "PMKID update command failed\n");
986 return ret;
987 }
988
989 return 0;
990}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index b36be2b23a3c..06af0552cd75 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -450,6 +450,25 @@ struct iwm_umac_cmd_stats_req {
450 __le32 flags; 450 __le32 flags;
451} __attribute__ ((packed)); 451} __attribute__ ((packed));
452 452
453struct iwm_umac_cmd_stop_resume_tx {
454 u8 flags;
455 u8 sta_id;
456 __le16 stop_resume_tid_msk;
457 __le16 last_seq_num[IWM_UMAC_TID_NR];
458 u16 reserved;
459} __attribute__ ((packed));
460
461#define IWM_CMD_PMKID_ADD 1
462#define IWM_CMD_PMKID_DEL 2
463#define IWM_CMD_PMKID_FLUSH 3
464
465struct iwm_umac_pmkid_update {
466 __le32 command;
467 u8 bssid[ETH_ALEN];
468 __le16 reserved;
469 u8 pmkid[WLAN_PMKID_LEN];
470} __attribute__ ((packed));
471
453/* LMAC commands */ 472/* LMAC commands */
454int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); 473int iwm_read_mac(struct iwm_priv *iwm, u8 *mac);
455int iwm_send_prio_table(struct iwm_priv *iwm); 474int iwm_send_prio_table(struct iwm_priv *iwm);
@@ -478,6 +497,10 @@ int iwm_send_umac_channel_list(struct iwm_priv *iwm);
478int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, 497int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
479 int ssid_num); 498 int ssid_num);
480int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); 499int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len);
500int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
501 struct iwm_umac_notif_stop_resume_tx *ntf);
502int iwm_send_pmkid_update(struct iwm_priv *iwm,
503 struct cfg80211_pmksa *pmksa, u32 command);
481 504
482/* UDMA commands */ 505/* UDMA commands */
483int iwm_target_reset(struct iwm_priv *iwm); 506int 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..be992ca41cf1 100644
--- a/drivers/net/wireless/iwmc3200wifi/debugfs.c
+++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c
@@ -158,6 +158,29 @@ static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer,
158 } 158 }
159 159
160 spin_unlock_irqrestore(&txq->queue.lock, flags); 160 spin_unlock_irqrestore(&txq->queue.lock, flags);
161
162 spin_lock_irqsave(&txq->stopped_queue.lock, flags);
163
164 len += snprintf(buf + len, buf_len - len,
165 "\tStopped Queue len: %d\n",
166 skb_queue_len(&txq->stopped_queue));
167 for (j = 0; j < skb_queue_len(&txq->stopped_queue); j++) {
168 struct iwm_tx_info *tx_info;
169
170 skb = skb->next;
171 tx_info = skb_to_tx_info(skb);
172
173 len += snprintf(buf + len, buf_len - len,
174 "\tSKB #%d\n", j);
175 len += snprintf(buf + len, buf_len - len,
176 "\t\tsta: %d\n", tx_info->sta);
177 len += snprintf(buf + len, buf_len - len,
178 "\t\tcolor: %d\n", tx_info->color);
179 len += snprintf(buf + len, buf_len - len,
180 "\t\ttid: %d\n", tx_info->tid);
181 }
182
183 spin_unlock_irqrestore(&txq->stopped_queue.lock, flags);
161 } 184 }
162 185
163 ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); 186 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..8091421ee5e5 100644
--- a/drivers/net/wireless/iwmc3200wifi/eeprom.c
+++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c
@@ -66,6 +66,10 @@ static struct iwm_eeprom_entry eeprom_map[] = {
66 [IWM_EEPROM_SKU_CAP] = 66 [IWM_EEPROM_SKU_CAP] =
67 {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN}, 67 {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN},
68 68
69 [IWM_EEPROM_FAT_CHANNELS_CAP] =
70 {"HT channels capabilities", IWM_EEPROM_FAT_CHANNELS_CAP_OFF,
71 IWM_EEPROM_FAT_CHANNELS_CAP_LEN},
72
69 [IWM_EEPROM_CALIB_RXIQ_OFFSET] = 73 [IWM_EEPROM_CALIB_RXIQ_OFFSET] =
70 {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN}, 74 {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN},
71 75
@@ -146,6 +150,52 @@ u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id)
146 return iwm->eeprom + eeprom_map[eeprom_id].offset; 150 return iwm->eeprom + eeprom_map[eeprom_id].offset;
147} 151}
148 152
153int iwm_eeprom_fat_channels(struct iwm_priv *iwm)
154{
155 struct wiphy *wiphy = iwm_to_wiphy(iwm);
156 struct ieee80211_supported_band *band;
157 u16 *channels, i;
158
159 channels = (u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_FAT_CHANNELS_CAP);
160 if (IS_ERR(channels))
161 return PTR_ERR(channels);
162
163 band = wiphy->bands[IEEE80211_BAND_2GHZ];
164 band->ht_cap.ht_supported = true;
165
166 for (i = 0; i < IWM_EEPROM_FAT_CHANNELS_24; i++)
167 if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED))
168 band->ht_cap.ht_supported = false;
169
170 band = wiphy->bands[IEEE80211_BAND_5GHZ];
171 band->ht_cap.ht_supported = true;
172 for (i = IWM_EEPROM_FAT_CHANNELS_24; i < IWM_EEPROM_FAT_CHANNELS; i++)
173 if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED))
174 band->ht_cap.ht_supported = false;
175
176 return 0;
177}
178
179u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm)
180{
181 u16 sku_cap;
182 u32 wireless_mode = 0;
183
184 sku_cap = *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP));
185
186 if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_24GHZ)
187 wireless_mode |= WIRELESS_MODE_11G;
188
189 if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_52GHZ)
190 wireless_mode |= WIRELESS_MODE_11A;
191
192 if (sku_cap & IWM_EEPROM_SKU_CAP_11N_ENABLE)
193 wireless_mode |= WIRELESS_MODE_11N;
194
195 return wireless_mode;
196}
197
198
149int iwm_eeprom_init(struct iwm_priv *iwm) 199int iwm_eeprom_init(struct iwm_priv *iwm)
150{ 200{
151 int i, ret = 0; 201 int i, ret = 0;
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.h b/drivers/net/wireless/iwmc3200wifi/eeprom.h
index cdb31a6a1f5f..4e3a3fdab0d3 100644
--- a/drivers/net/wireless/iwmc3200wifi/eeprom.h
+++ b/drivers/net/wireless/iwmc3200wifi/eeprom.h
@@ -48,6 +48,7 @@ enum {
48 IWM_EEPROM_CARD_ID, 48 IWM_EEPROM_CARD_ID,
49 IWM_EEPROM_RADIO_CONF, 49 IWM_EEPROM_RADIO_CONF,
50 IWM_EEPROM_SKU_CAP, 50 IWM_EEPROM_SKU_CAP,
51 IWM_EEPROM_FAT_CHANNELS_CAP,
51 52
52 IWM_EEPROM_INDIRECT_OFFSET, 53 IWM_EEPROM_INDIRECT_OFFSET,
53 IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET, 54 IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET,
@@ -58,14 +59,15 @@ enum {
58 IWM_EEPROM_LAST, 59 IWM_EEPROM_LAST,
59}; 60};
60 61
61#define IWM_EEPROM_SIG_OFF 0x00 62#define IWM_EEPROM_SIG_OFF 0x00
62#define IWM_EEPROM_VERSION_OFF (0x54 << 1) 63#define IWM_EEPROM_VERSION_OFF (0x54 << 1)
63#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1) 64#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1)
64#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1) 65#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1)
65#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1) 66#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1)
66#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1) 67#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1)
67#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1) 68#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1)
68#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1) 69#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1)
70#define IWM_EEPROM_FAT_CHANNELS_CAP_OFF (0xde << 1)
69 71
70#define IWM_EEPROM_SIG_LEN 4 72#define IWM_EEPROM_SIG_LEN 4
71#define IWM_EEPROM_VERSION_LEN 2 73#define IWM_EEPROM_VERSION_LEN 2
@@ -74,6 +76,7 @@ enum {
74#define IWM_EEPROM_CARD_ID_LEN 2 76#define IWM_EEPROM_CARD_ID_LEN 2
75#define IWM_EEPROM_RADIO_CONF_LEN 2 77#define IWM_EEPROM_RADIO_CONF_LEN 2
76#define IWM_EEPROM_SKU_CAP_LEN 2 78#define IWM_EEPROM_SKU_CAP_LEN 2
79#define IWM_EEPROM_FAT_CHANNELS_CAP_LEN 40
77#define IWM_EEPROM_INDIRECT_LEN 2 80#define IWM_EEPROM_INDIRECT_LEN 2
78 81
79#define IWM_MAX_EEPROM_DATA_LEN 240 82#define IWM_MAX_EEPROM_DATA_LEN 240
@@ -87,6 +90,14 @@ enum {
87#define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5) 90#define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5)
88#define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6) 91#define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6)
89 92
93#define IWM_EEPROM_FAT_CHANNELS 20
94/* 2.4 gHz FAT primary channels: 1, 2, 3, 4, 5, 6, 7, 8, 9 */
95#define IWM_EEPROM_FAT_CHANNELS_24 9
96/* 5.2 gHz FAT primary channels: 36,44,52,60,100,108,116,124,132,149,157 */
97#define IWM_EEPROM_FAT_CHANNELS_52 11
98
99#define IWM_EEPROM_FAT_CHANNEL_ENABLED (1 << 0)
100
90enum { 101enum {
91 IWM_EEPROM_CALIB_CAL_HDR, 102 IWM_EEPROM_CALIB_CAL_HDR,
92 IWM_EEPROM_CALIB_TX_POWER, 103 IWM_EEPROM_CALIB_TX_POWER,
@@ -110,5 +121,7 @@ struct iwm_eeprom_entry {
110int iwm_eeprom_init(struct iwm_priv *iwm); 121int iwm_eeprom_init(struct iwm_priv *iwm);
111void iwm_eeprom_exit(struct iwm_priv *iwm); 122void iwm_eeprom_exit(struct iwm_priv *iwm);
112u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id); 123u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id);
124int iwm_eeprom_fat_channels(struct iwm_priv *iwm);
125u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm);
113 126
114#endif 127#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index a9bf6bc97bea..5a26bb05a33a 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -81,7 +81,6 @@ struct iwm_conf {
81 u32 assoc_timeout; 81 u32 assoc_timeout;
82 u32 roam_timeout; 82 u32 roam_timeout;
83 u32 wireless_mode; 83 u32 wireless_mode;
84 u32 coexist_mode;
85 84
86 u8 ibss_band; 85 u8 ibss_band;
87 u8 ibss_channel; 86 u8 ibss_channel;
@@ -131,11 +130,18 @@ struct iwm_notif {
131 unsigned long buf_size; 130 unsigned long buf_size;
132}; 131};
133 132
133struct iwm_tid_info {
134 __le16 last_seq_num;
135 bool stopped;
136 struct mutex mutex;
137};
138
134struct iwm_sta_info { 139struct iwm_sta_info {
135 u8 addr[ETH_ALEN]; 140 u8 addr[ETH_ALEN];
136 bool valid; 141 bool valid;
137 bool qos; 142 bool qos;
138 u8 color; 143 u8 color;
144 struct iwm_tid_info tid_info[IWM_UMAC_TID_NR];
139}; 145};
140 146
141struct iwm_tx_info { 147struct iwm_tx_info {
@@ -185,6 +191,8 @@ struct iwm_key {
185struct iwm_tx_queue { 191struct iwm_tx_queue {
186 int id; 192 int id;
187 struct sk_buff_head queue; 193 struct sk_buff_head queue;
194 struct sk_buff_head stopped_queue;
195 spinlock_t lock;
188 struct workqueue_struct *wq; 196 struct workqueue_struct *wq;
189 struct work_struct worker; 197 struct work_struct worker;
190 u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE]; 198 u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE];
@@ -341,6 +349,7 @@ int iwm_up(struct iwm_priv *iwm);
341int iwm_down(struct iwm_priv *iwm); 349int iwm_down(struct iwm_priv *iwm);
342 350
343/* TX API */ 351/* TX API */
352u16 iwm_tid_to_queue(u16 tid);
344void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); 353void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages);
345void iwm_tx_worker(struct work_struct *work); 354void iwm_tx_worker(struct work_struct *work);
346int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); 355int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 75f105a59543..7f34d6dd3c41 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -68,7 +68,6 @@ static struct iwm_conf def_iwm_conf = {
68 .ct_kill_exit = 110, 68 .ct_kill_exit = 110,
69 .reset_on_fatal_err = 1, 69 .reset_on_fatal_err = 1,
70 .auto_connect = 1, 70 .auto_connect = 1,
71 .wimax_not_present = 0,
72 .enable_qos = 1, 71 .enable_qos = 1,
73 .mode = UMAC_MODE_BSS, 72 .mode = UMAC_MODE_BSS,
74 73
@@ -80,8 +79,8 @@ static struct iwm_conf def_iwm_conf = {
80 79
81 .assoc_timeout = 2, 80 .assoc_timeout = 2,
82 .roam_timeout = 10, 81 .roam_timeout = 10,
83 .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G, 82 .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G |
84 .coexist_mode = COEX_MODE_CM, 83 WIRELESS_MODE_11N,
85 84
86 /* IBSS */ 85 /* IBSS */
87 .ibss_band = UMAC_BAND_2GHZ, 86 .ibss_band = UMAC_BAND_2GHZ,
@@ -94,6 +93,10 @@ static int modparam_reset;
94module_param_named(reset, modparam_reset, bool, 0644); 93module_param_named(reset, modparam_reset, bool, 0644);
95MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])"); 94MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])");
96 95
96static int modparam_wimax_enable = 1;
97module_param_named(wimax_enable, modparam_wimax_enable, bool, 0644);
98MODULE_PARM_DESC(wimax_enable, "Enable wimax core (default 1 [wimax enabled])");
99
97int iwm_mode_to_nl80211_iftype(int mode) 100int iwm_mode_to_nl80211_iftype(int mode)
98{ 101{
99 switch (mode) { 102 switch (mode) {
@@ -247,7 +250,7 @@ static void iwm_watchdog(unsigned long data)
247 250
248int iwm_priv_init(struct iwm_priv *iwm) 251int iwm_priv_init(struct iwm_priv *iwm)
249{ 252{
250 int i; 253 int i, j;
251 char name[32]; 254 char name[32];
252 255
253 iwm->status = 0; 256 iwm->status = 0;
@@ -291,6 +294,8 @@ int iwm_priv_init(struct iwm_priv *iwm)
291 return -EAGAIN; 294 return -EAGAIN;
292 295
293 skb_queue_head_init(&iwm->txq[i].queue); 296 skb_queue_head_init(&iwm->txq[i].queue);
297 skb_queue_head_init(&iwm->txq[i].stopped_queue);
298 spin_lock_init(&iwm->txq[i].lock);
294 } 299 }
295 300
296 for (i = 0; i < IWM_NUM_KEYS; i++) 301 for (i = 0; i < IWM_NUM_KEYS; i++)
@@ -298,6 +303,12 @@ int iwm_priv_init(struct iwm_priv *iwm)
298 303
299 iwm->default_key = -1; 304 iwm->default_key = -1;
300 305
306 for (i = 0; i < IWM_STA_TABLE_NUM; i++)
307 for (j = 0; j < IWM_UMAC_TID_NR; j++) {
308 mutex_init(&iwm->sta_table[i].tid_info[j].mutex);
309 iwm->sta_table[i].tid_info[j].stopped = false;
310 }
311
301 init_timer(&iwm->watchdog); 312 init_timer(&iwm->watchdog);
302 iwm->watchdog.function = iwm_watchdog; 313 iwm->watchdog.function = iwm_watchdog;
303 iwm->watchdog.data = (unsigned long)iwm; 314 iwm->watchdog.data = (unsigned long)iwm;
@@ -478,7 +489,7 @@ static int iwm_config_boot_params(struct iwm_priv *iwm)
478 int ret; 489 int ret;
479 490
480 /* check Wimax is off and config debug monitor */ 491 /* check Wimax is off and config debug monitor */
481 if (iwm->conf.wimax_not_present) { 492 if (!modparam_wimax_enable) {
482 u32 data1 = 0x1f; 493 u32 data1 = 0x1f;
483 u32 addr1 = 0x606BE258; 494 u32 addr1 = 0x606BE258;
484 495
@@ -571,6 +582,7 @@ void iwm_link_off(struct iwm_priv *iwm)
571 582
572 for (i = 0; i < IWM_TX_QUEUES; i++) { 583 for (i = 0; i < IWM_TX_QUEUES; i++) {
573 skb_queue_purge(&iwm->txq[i].queue); 584 skb_queue_purge(&iwm->txq[i].queue);
585 skb_queue_purge(&iwm->txq[i].stopped_queue);
574 586
575 iwm->txq[i].concat_count = 0; 587 iwm->txq[i].concat_count = 0;
576 iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf; 588 iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf;
@@ -630,6 +642,7 @@ static int __iwm_up(struct iwm_priv *iwm)
630 int ret; 642 int ret;
631 struct iwm_notif *notif_reboot, *notif_ack = NULL; 643 struct iwm_notif *notif_reboot, *notif_ack = NULL;
632 struct wiphy *wiphy = iwm_to_wiphy(iwm); 644 struct wiphy *wiphy = iwm_to_wiphy(iwm);
645 u32 wireless_mode;
633 646
634 ret = iwm_bus_enable(iwm); 647 ret = iwm_bus_enable(iwm);
635 if (ret) { 648 if (ret) {
@@ -691,6 +704,27 @@ static int __iwm_up(struct iwm_priv *iwm)
691 goto err_disable; 704 goto err_disable;
692 } 705 }
693 706
707 ret = iwm_eeprom_fat_channels(iwm);
708 if (ret) {
709 IWM_ERR(iwm, "Couldnt read HT channels EEPROM entries\n");
710 goto err_fw;
711 }
712
713 /*
714 * Read our SKU capabilities.
715 * If it's valid, we AND the configured wireless mode with the
716 * device EEPROM value as the current profile wireless mode.
717 */
718 wireless_mode = iwm_eeprom_wireless_mode(iwm);
719 if (wireless_mode) {
720 iwm->conf.wireless_mode &= wireless_mode;
721 if (iwm->umac_profile)
722 iwm->umac_profile->wireless_mode =
723 iwm->conf.wireless_mode;
724 } else
725 IWM_ERR(iwm, "Wrong SKU capabilities: 0x%x\n",
726 *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP)));
727
694 snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s", 728 snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s",
695 iwm->lmac_version, iwm->umac_version); 729 iwm->lmac_version, iwm->umac_version);
696 730
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index 4f8dbdd7b917..e4f0f8705f65 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -76,6 +76,14 @@ static int iwm_stop(struct net_device *ndev)
76 */ 76 */
77static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; 77static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
78 78
79u16 iwm_tid_to_queue(u16 tid)
80{
81 if (tid > IWM_UMAC_TID_NR - 2)
82 return -EINVAL;
83
84 return iwm_1d_to_queue[tid];
85}
86
79static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) 87static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb)
80{ 88{
81 skb->priority = cfg80211_classify8021d(skb); 89 skb->priority = cfg80211_classify8021d(skb);
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index bdb1d7e7979d..72c27a3e5528 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -1087,6 +1087,71 @@ static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf,
1087 return 0; 1087 return 0;
1088} 1088}
1089 1089
1090static int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf,
1091 unsigned long buf_size,
1092 struct iwm_wifi_cmd *cmd)
1093{
1094 struct iwm_umac_notif_stop_resume_tx *stp_res_tx =
1095 (struct iwm_umac_notif_stop_resume_tx *)buf;
1096 struct iwm_sta_info *sta_info;
1097 struct iwm_tid_info *tid_info;
1098 u8 sta_id = STA_ID_N_COLOR_ID(stp_res_tx->sta_id);
1099 u16 tid_msk = le16_to_cpu(stp_res_tx->stop_resume_tid_msk);
1100 int bit, ret = 0;
1101 bool stop = false;
1102
1103 IWM_DBG_NTF(iwm, DBG, "stop/resume notification:\n"
1104 "\tflags: 0x%x\n"
1105 "\tSTA id: %d\n"
1106 "\tTID bitmask: 0x%x\n",
1107 stp_res_tx->flags, stp_res_tx->sta_id,
1108 stp_res_tx->stop_resume_tid_msk);
1109
1110 if (stp_res_tx->flags & UMAC_STOP_TX_FLAG)
1111 stop = true;
1112
1113 sta_info = &iwm->sta_table[sta_id];
1114 if (!sta_info->valid) {
1115 IWM_ERR(iwm, "Stoping an invalid STA: %d %d\n",
1116 sta_id, stp_res_tx->sta_id);
1117 return -EINVAL;
1118 }
1119
1120 for_each_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 u16 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
1090static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, 1155static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
1091 unsigned long buf_size, 1156 unsigned long buf_size,
1092 struct iwm_wifi_cmd *cmd) 1157 struct iwm_wifi_cmd *cmd)
@@ -1371,6 +1436,7 @@ static const iwm_handler iwm_umac_handlers[] =
1371 [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics, 1436 [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics,
1372 [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy, 1437 [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy,
1373 [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,
1374 [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, 1440 [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet,
1375 [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper, 1441 [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper,
1376}; 1442};
diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c
index e3b4f7902daf..55905f02309c 100644
--- a/drivers/net/wireless/iwmc3200wifi/tx.c
+++ b/drivers/net/wireless/iwmc3200wifi/tx.c
@@ -329,7 +329,7 @@ static int iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb,
329 329
330 memcpy(buf + sizeof(*hdr), skb->data, skb->len); 330 memcpy(buf + sizeof(*hdr), skb->data, skb->len);
331 331
332 return 0; 332 return umac_cmd.seq_num;
333} 333}
334 334
335static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, 335static int iwm_tx_send_concat_packets(struct iwm_priv *iwm,
@@ -354,16 +354,15 @@ static int iwm_tx_send_concat_packets(struct iwm_priv *iwm,
354 return ret; 354 return ret;
355} 355}
356 356
357#define CONFIG_IWM_TX_CONCATENATED 1
358
359void iwm_tx_worker(struct work_struct *work) 357void iwm_tx_worker(struct work_struct *work)
360{ 358{
361 struct iwm_priv *iwm; 359 struct iwm_priv *iwm;
362 struct iwm_tx_info *tx_info = NULL; 360 struct iwm_tx_info *tx_info = NULL;
363 struct sk_buff *skb; 361 struct sk_buff *skb;
364 int cmdlen, ret;
365 struct iwm_tx_queue *txq; 362 struct iwm_tx_queue *txq;
366 int pool_id; 363 struct iwm_sta_info *sta_info;
364 struct iwm_tid_info *tid_info;
365 int cmdlen, ret, pool_id;
367 366
368 txq = container_of(work, struct iwm_tx_queue, worker); 367 txq = container_of(work, struct iwm_tx_queue, worker);
369 iwm = container_of(txq, struct iwm_priv, txq[txq->id]); 368 iwm = container_of(txq, struct iwm_priv, txq[txq->id]);
@@ -373,19 +372,46 @@ void iwm_tx_worker(struct work_struct *work)
373 while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) && 372 while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) &&
374 !skb_queue_empty(&txq->queue)) { 373 !skb_queue_empty(&txq->queue)) {
375 374
375 spin_lock_bh(&txq->lock);
376 skb = skb_dequeue(&txq->queue); 376 skb = skb_dequeue(&txq->queue);
377 spin_unlock_bh(&txq->lock);
378
377 tx_info = skb_to_tx_info(skb); 379 tx_info = skb_to_tx_info(skb);
380 sta_info = &iwm->sta_table[tx_info->sta];
381 if (!sta_info->valid) {
382 IWM_ERR(iwm, "Trying to send a frame to unknown STA\n");
383 kfree_skb(skb);
384 continue;
385 }
386
387 tid_info = &sta_info->tid_info[tx_info->tid];
388
389 mutex_lock(&tid_info->mutex);
390
391 /*
392 * If the RAxTID is stopped, we queue the skb to the stopped
393 * queue.
394 * Whenever we'll get a UMAC notification to resume the tx flow
395 * for this RAxTID, we'll merge back the stopped queue into the
396 * regular queue. See iwm_ntf_stop_resume_tx() from rx.c.
397 */
398 if (tid_info->stopped) {
399 IWM_DBG_TX(iwm, DBG, "%dx%d stopped\n",
400 tx_info->sta, tx_info->tid);
401 spin_lock_bh(&txq->lock);
402 skb_queue_tail(&txq->stopped_queue, skb);
403 spin_unlock_bh(&txq->lock);
404
405 mutex_unlock(&tid_info->mutex);
406 continue;
407 }
408
378 cmdlen = IWM_UDMA_HDR_LEN + skb->len; 409 cmdlen = IWM_UDMA_HDR_LEN + skb->len;
379 410
380 IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: " 411 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, 412 "%d, color: %d\n", txq->id, skb, tx_info->sta,
382 tx_info->color); 413 tx_info->color);
383 414
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) 415 if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE)
390 iwm_tx_send_concat_packets(iwm, txq); 416 iwm_tx_send_concat_packets(iwm, txq);
391 417
@@ -393,14 +419,21 @@ void iwm_tx_worker(struct work_struct *work)
393 if (ret) { 419 if (ret) {
394 IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue " 420 IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue "
395 "%d, Tx worker stopped\n", txq->id); 421 "%d, Tx worker stopped\n", txq->id);
422 spin_lock_bh(&txq->lock);
396 skb_queue_head(&txq->queue, skb); 423 skb_queue_head(&txq->queue, skb);
424 spin_unlock_bh(&txq->lock);
425
426 mutex_unlock(&tid_info->mutex);
397 break; 427 break;
398 } 428 }
399 429
400 txq->concat_ptr = txq->concat_buf + txq->concat_count; 430 txq->concat_ptr = txq->concat_buf + txq->concat_count;
401 iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); 431 tid_info->last_seq_num =
432 iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr);
402 txq->concat_count += ALIGN(cmdlen, 16); 433 txq->concat_count += ALIGN(cmdlen, 16);
403#endif 434
435 mutex_unlock(&tid_info->mutex);
436
404 kfree_skb(skb); 437 kfree_skb(skb);
405 } 438 }
406 439
@@ -419,14 +452,14 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
419 struct iwm_priv *iwm = ndev_to_iwm(netdev); 452 struct iwm_priv *iwm = ndev_to_iwm(netdev);
420 struct net_device *ndev = iwm_to_ndev(iwm); 453 struct net_device *ndev = iwm_to_ndev(iwm);
421 struct wireless_dev *wdev = iwm_to_wdev(iwm); 454 struct wireless_dev *wdev = iwm_to_wdev(iwm);
422 u8 *dst_addr;
423 struct iwm_tx_info *tx_info; 455 struct iwm_tx_info *tx_info;
424 struct iwm_tx_queue *txq; 456 struct iwm_tx_queue *txq;
425 struct iwm_sta_info *sta_info; 457 struct iwm_sta_info *sta_info;
426 u8 sta_id; 458 u8 *dst_addr, sta_id;
427 u16 queue; 459 u16 queue;
428 int ret; 460 int ret;
429 461
462
430 if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { 463 if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
431 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: " 464 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: "
432 "not associated\n"); 465 "not associated\n");
@@ -440,7 +473,8 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
440 txq = &iwm->txq[queue]; 473 txq = &iwm->txq[queue];
441 474
442 /* No free space for Tx, tx_worker is too slow */ 475 /* No free space for Tx, tx_worker is too slow */
443 if (skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) { 476 if ((skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) ||
477 (skb_queue_len(&txq->stopped_queue) > IWM_TX_LIST_SIZE)) {
444 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue); 478 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue);
445 netif_stop_subqueue(netdev, queue); 479 netif_stop_subqueue(netdev, queue);
446 return NETDEV_TX_BUSY; 480 return NETDEV_TX_BUSY;
@@ -477,7 +511,9 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
477 else 511 else
478 tx_info->tid = IWM_UMAC_MGMT_TID; 512 tx_info->tid = IWM_UMAC_MGMT_TID;
479 513
514 spin_lock_bh(&iwm->txq[queue].lock);
480 skb_queue_tail(&iwm->txq[queue].queue, skb); 515 skb_queue_tail(&iwm->txq[queue].queue, skb);
516 spin_unlock_bh(&iwm->txq[queue].lock);
481 517
482 queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); 518 queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker);
483 519
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index be903543bb47..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 */
@@ -691,13 +709,13 @@ struct iwm_umac_notif_rx_ticket {
691#define UMAC_PHY_NUM_CHAINS 3 709#define UMAC_PHY_NUM_CHAINS 3
692 710
693#define IWM_UMAC_MGMT_TID 8 711#define IWM_UMAC_MGMT_TID 8
694#define IWM_UMAC_TID_NR 8 712#define IWM_UMAC_TID_NR 9 /* 8 TIDs + MGMT */
695 713
696struct iwm_umac_notif_stats { 714struct iwm_umac_notif_stats {
697 struct iwm_umac_wifi_in_hdr hdr; 715 struct iwm_umac_wifi_in_hdr hdr;
698 __le32 flags; 716 __le32 flags;
699 __le32 timestamp; 717 __le32 timestamp;
700 __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 */
701 __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; 719 __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR];
702 __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; 720 __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR];
703 __le32 chain_energy[UMAC_PHY_NUM_CHAINS]; 721 __le32 chain_energy[UMAC_PHY_NUM_CHAINS];
@@ -742,6 +760,20 @@ struct iwm_umac_notif_stats {
742 __le32 roam_ap_loadblance; 760 __le32 roam_ap_loadblance;
743} __attribute__ ((packed)); 761} __attribute__ ((packed));
744 762
763#define UMAC_STOP_TX_FLAG 0x1
764#define UMAC_RESUME_TX_FLAG 0x2
765
766#define LAST_SEQ_NUM_INVALID 0xFFFF
767
768struct iwm_umac_notif_stop_resume_tx {
769 struct iwm_umac_wifi_in_hdr hdr;
770 u8 flags; /* UMAC_*_TX_FLAG_* */
771 u8 sta_id;
772 __le16 stop_resume_tid_msk; /* tid bitmask */
773} __attribute__ ((packed));
774
775#define UMAC_MAX_NUM_PMKIDS 4
776
745/* WiFi interface wrapper header */ 777/* WiFi interface wrapper header */
746struct iwm_umac_wifi_if { 778struct iwm_umac_wifi_if {
747 u8 oid; 779 u8 oid;