aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2011-08-17 03:45:49 -0400
committerLuciano Coelho <coelho@ti.com>2011-08-22 05:35:27 -0400
commit0f9c8250e10a16f48f82ffda3a5a7cb9e7b4a9ee (patch)
tree32762d2ec797422fd152d4a7bc3c920104a47808 /drivers/net/wireless/wl12xx
parente51ae9be2e313b63a43f1f93578d9a71d38a77ea (diff)
wl12xx: re-enable block ack session support
Incorporate interface changes for HT support. Add ba_bitmap field to the wl1271_link struct, to indicate activate RX BA sessions (for AP mode). Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r--drivers/net/wireless/wl12xx/acx.c66
-rw-r--r--drivers/net/wireless/wl12xx/acx.h82
-rw-r--r--drivers/net/wireless/wl12xx/cmd.h1
-rw-r--r--drivers/net/wireless/wl12xx/conf.h9
-rw-r--r--drivers/net/wireless/wl12xx/init.c37
-rw-r--r--drivers/net/wireless/wl12xx/main.c146
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h6
7 files changed, 177 insertions, 170 deletions
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index d783fce45613..ecbceb6f1ea9 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1323,19 +1323,15 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
1323 goto out; 1323 goto out;
1324 } 1324 }
1325 1325
1326 /* Allow HT Operation ? */
1327 if (allow_ht_operation) { 1326 if (allow_ht_operation) {
1328 ht_capabilites = 1327 /* no need to translate capabilities - use the spec values */
1329 WL1271_ACX_FW_CAP_HT_OPERATION; 1328 ht_capabilites = ht_cap->cap;
1330 if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) 1329
1331 ht_capabilites |= 1330 /*
1332 WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; 1331 * this bit is not employed by the spec but only by FW to
1333 if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) 1332 * indicate peer HT support
1334 ht_capabilites |= 1333 */
1335 WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; 1334 ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION;
1336 if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT)
1337 ht_capabilites |=
1338 WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION;
1339 1335
1340 /* get data from A-MPDU parameters field */ 1336 /* get data from A-MPDU parameters field */
1341 acx->ampdu_max_length = ht_cap->ampdu_factor; 1337 acx->ampdu_max_length = ht_cap->ampdu_factor;
@@ -1392,14 +1388,12 @@ out:
1392} 1388}
1393 1389
1394/* Configure BA session initiator/receiver parameters setting in the FW. */ 1390/* Configure BA session initiator/receiver parameters setting in the FW. */
1395int wl1271_acx_set_ba_session(struct wl1271 *wl, 1391int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl)
1396 enum ieee80211_back_parties direction,
1397 u8 tid_index, u8 policy)
1398{ 1392{
1399 struct wl1271_acx_ba_session_policy *acx; 1393 struct wl1271_acx_ba_initiator_policy *acx;
1400 int ret; 1394 int ret;
1401 1395
1402 wl1271_debug(DEBUG_ACX, "acx ba session setting"); 1396 wl1271_debug(DEBUG_ACX, "acx ba initiator policy");
1403 1397
1404 acx = kzalloc(sizeof(*acx), GFP_KERNEL); 1398 acx = kzalloc(sizeof(*acx), GFP_KERNEL);
1405 if (!acx) { 1399 if (!acx) {
@@ -1407,33 +1401,18 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl,
1407 goto out; 1401 goto out;
1408 } 1402 }
1409 1403
1410 /* ANY role */ 1404 /* set for the current role */
1411 acx->role_id = 0xff; 1405 acx->role_id = wl->role_id;
1412 acx->tid = tid_index; 1406 acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap;
1413 acx->enable = policy; 1407 acx->win_size = wl->conf.ht.tx_ba_win_size;
1414 acx->ba_direction = direction; 1408 acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;
1415
1416 switch (direction) {
1417 case WLAN_BACK_INITIATOR:
1418 acx->win_size = wl->conf.ht.tx_ba_win_size;
1419 acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;
1420 break;
1421 case WLAN_BACK_RECIPIENT:
1422 acx->win_size = RX_BA_WIN_SIZE;
1423 acx->inactivity_timeout = 0;
1424 break;
1425 default:
1426 wl1271_error("Incorrect acx command id=%x\n", direction);
1427 ret = -EINVAL;
1428 goto out;
1429 }
1430 1409
1431 ret = wl1271_cmd_configure(wl, 1410 ret = wl1271_cmd_configure(wl,
1432 ACX_BA_SESSION_POLICY_CFG, 1411 ACX_BA_SESSION_INIT_POLICY,
1433 acx, 1412 acx,
1434 sizeof(*acx)); 1413 sizeof(*acx));
1435 if (ret < 0) { 1414 if (ret < 0) {
1436 wl1271_warning("acx ba session setting failed: %d", ret); 1415 wl1271_warning("acx ba initiator policy failed: %d", ret);
1437 goto out; 1416 goto out;
1438 } 1417 }
1439 1418
@@ -1443,8 +1422,8 @@ out:
1443} 1422}
1444 1423
1445/* setup BA session receiver setting in the FW. */ 1424/* setup BA session receiver setting in the FW. */
1446int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, 1425int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
1447 bool enable) 1426 u16 ssn, bool enable, u8 peer_hlid)
1448{ 1427{
1449 struct wl1271_acx_ba_receiver_setup *acx; 1428 struct wl1271_acx_ba_receiver_setup *acx;
1450 int ret; 1429 int ret;
@@ -1457,11 +1436,10 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
1457 goto out; 1436 goto out;
1458 } 1437 }
1459 1438
1460 /* Single link for now */ 1439 acx->hlid = peer_hlid;
1461 acx->link_id = 1;
1462 acx->tid = tid_index; 1440 acx->tid = tid_index;
1463 acx->enable = enable; 1441 acx->enable = enable;
1464 acx->win_size = 0; 1442 acx->win_size = wl->conf.ht.rx_ba_win_size;
1465 acx->ssn = ssn; 1443 acx->ssn = ssn;
1466 1444
1467 ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, 1445 ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx,
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 5b3fabde0afe..82c9271b4e84 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -899,6 +899,10 @@ struct wl1271_acx_rssi_snr_avg_weights {
899 u8 snr_data; 899 u8 snr_data;
900}; 900};
901 901
902
903/* special capability bit (not employed by the 802.11n spec) */
904#define WL12XX_HT_CAP_HT_OPERATION BIT(16)
905
902/* 906/*
903 * ACX_PEER_HT_CAP 907 * ACX_PEER_HT_CAP
904 * Configure HT capabilities - declare the capabilities of the peer 908 * Configure HT capabilities - declare the capabilities of the peer
@@ -907,19 +911,7 @@ struct wl1271_acx_rssi_snr_avg_weights {
907struct wl1271_acx_ht_capabilities { 911struct wl1271_acx_ht_capabilities {
908 struct acx_header header; 912 struct acx_header header;
909 913
910 /* 914 /* bitmask of capability bits supported by the peer */
911 * bit 0 - Allow HT Operation
912 * bit 1 - Allow Greenfield format in TX
913 * bit 2 - Allow Short GI in TX
914 * bit 3 - Allow L-SIG TXOP Protection in TX
915 * bit 4 - Allow HT Control fields in TX.
916 * Note, driver will still leave space for HT control in packets
917 * regardless of the value of this field. FW will be responsible
918 * to drop the HT field from any frame when this Bit set to 0.
919 * bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD.
920 * Exact policy setting for this feature is TBD.
921 * Note, this bit can only be set to 1 if bit 3 is set to 1.
922 */
923 __le32 ht_capabilites; 915 __le32 ht_capabilites;
924 916
925 /* Indicates to which link these capabilities apply. */ 917 /* Indicates to which link these capabilities apply. */
@@ -937,15 +929,6 @@ struct wl1271_acx_ht_capabilities {
937 u8 padding; 929 u8 padding;
938} __packed; 930} __packed;
939 931
940/* HT Capabilites Fw Bit Mask Mapping */
941#define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0)
942#define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1)
943#define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2)
944#define WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION BIT(3)
945#define WL1271_ACX_FW_CAP_HT_CONTROL_FIELDS BIT(4)
946#define WL1271_ACX_FW_CAP_RD_INITIATION BIT(5)
947
948
949/* 932/*
950 * ACX_HT_BSS_OPERATION 933 * ACX_HT_BSS_OPERATION
951 * Configure HT capabilities - AP rules for behavior in the BSS. 934 * Configure HT capabilities - AP rules for behavior in the BSS.
@@ -979,57 +962,48 @@ struct wl1271_acx_ht_information {
979 u8 padding[2]; 962 u8 padding[2];
980} __packed; 963} __packed;
981 964
982#define RX_BA_WIN_SIZE 8 965#define RX_BA_MAX_SESSIONS 2
983 966
984struct wl1271_acx_ba_session_policy { 967struct wl1271_acx_ba_initiator_policy {
985 struct acx_header header; 968 struct acx_header header;
986 /* 969
987 * Specifies role Id, Range 0-7, 0xFF means ANY role. 970 /* Specifies role Id, Range 0-7, 0xFF means ANY role. */
988 * Future use. For now this field is irrelevant
989 */
990 u8 role_id; 971 u8 role_id;
972
991 /* 973 /*
992 * Specifies Link Id, Range 0-31, 0xFF means ANY Link Id. 974 * Per TID setting for allowing TX BA. Set a bit to 1 to allow
993 * Not applicable if Role Id is set to ANY. 975 * TX BA sessions for the corresponding TID.
994 */ 976 */
995 u8 link_id; 977 u8 tid_bitmap;
996
997 u8 tid;
998
999 u8 enable;
1000 978
1001 /* Windows size in number of packets */ 979 /* Windows size in number of packets */
1002 u16 win_size; 980 u8 win_size;
1003 981
1004 /* 982 u8 padding1[1];
1005 * As initiator inactivity timeout in time units(TU) of 1024us.
1006 * As receiver reserved
1007 */
1008 u16 inactivity_timeout;
1009 983
1010 /* Initiator = 1/Receiver = 0 */ 984 /* As initiator inactivity timeout in time units(TU) of 1024us */
1011 u8 ba_direction; 985 u16 inactivity_timeout;
1012 986
1013 u8 padding[3]; 987 u8 padding[2];
1014} __packed; 988} __packed;
1015 989
1016struct wl1271_acx_ba_receiver_setup { 990struct wl1271_acx_ba_receiver_setup {
1017 struct acx_header header; 991 struct acx_header header;
1018 992
1019 /* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */ 993 /* Specifies link id, range 0-31 */
1020 u8 link_id; 994 u8 hlid;
1021 995
1022 u8 tid; 996 u8 tid;
1023 997
1024 u8 enable; 998 u8 enable;
1025 999
1026 u8 padding[1];
1027
1028 /* Windows size in number of packets */ 1000 /* Windows size in number of packets */
1029 u16 win_size; 1001 u8 win_size;
1030 1002
1031 /* BA session starting sequence number. RANGE 0-FFF */ 1003 /* BA session starting sequence number. RANGE 0-FFF */
1032 u16 ssn; 1004 u16 ssn;
1005
1006 u8 padding[2];
1033} __packed; 1007} __packed;
1034 1008
1035struct wl1271_acx_fw_tsf_information { 1009struct wl1271_acx_fw_tsf_information {
@@ -1218,7 +1192,7 @@ enum {
1218 ACX_RSSI_SNR_WEIGHTS = 0x0052, 1192 ACX_RSSI_SNR_WEIGHTS = 0x0052,
1219 ACX_KEEP_ALIVE_MODE = 0x0053, 1193 ACX_KEEP_ALIVE_MODE = 0x0053,
1220 ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, 1194 ACX_SET_KEEP_ALIVE_CONFIG = 0x0054,
1221 ACX_BA_SESSION_POLICY_CFG = 0x0055, 1195 ACX_BA_SESSION_INIT_POLICY = 0x0055,
1222 ACX_BA_SESSION_RX_SETUP = 0x0056, 1196 ACX_BA_SESSION_RX_SETUP = 0x0056,
1223 ACX_PEER_HT_CAP = 0x0057, 1197 ACX_PEER_HT_CAP = 0x0057,
1224 ACX_HT_BSS_OPERATION = 0x0058, 1198 ACX_HT_BSS_OPERATION = 0x0058,
@@ -1297,11 +1271,9 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
1297 bool allow_ht_operation); 1271 bool allow_ht_operation);
1298int wl1271_acx_set_ht_information(struct wl1271 *wl, 1272int wl1271_acx_set_ht_information(struct wl1271 *wl,
1299 u16 ht_operation_mode); 1273 u16 ht_operation_mode);
1300int wl1271_acx_set_ba_session(struct wl1271 *wl, 1274int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl);
1301 enum ieee80211_back_parties direction, 1275int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
1302 u8 tid_index, u8 policy); 1276 u16 ssn, bool enable, u8 peer_hlid);
1303int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
1304 bool enable);
1305int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); 1277int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
1306int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable); 1278int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
1307int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); 1279int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 5cf92e256641..8b32a57e1cc6 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -208,6 +208,7 @@ enum {
208 CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ 208 CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/
209 CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ 209 CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/
210 CMD_STATUS_TEMPLATE_OOM = 23, 210 CMD_STATUS_TEMPLATE_OOM = 23,
211 CMD_STATUS_NO_RX_BA_SESSION = 24,
211 MAX_COMMAND_STATUS = 0xff 212 MAX_COMMAND_STATUS = 0xff
212}; 213};
213 214
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index a7c147838ab8..76b5c6233da4 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -557,6 +557,9 @@ struct conf_tx_ac_category {
557 557
558#define CONF_TX_MAX_TID_COUNT 8 558#define CONF_TX_MAX_TID_COUNT 8
559 559
560/* Allow TX BA on all TIDs but 6,7. These are currently reserved in the FW */
561#define CONF_TX_BA_ENABLED_TID_BITMAP 0x3F
562
560enum { 563enum {
561 CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ 564 CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/
562 CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/ 565 CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/
@@ -1095,8 +1098,12 @@ struct conf_rf_settings {
1095}; 1098};
1096 1099
1097struct conf_ht_setting { 1100struct conf_ht_setting {
1098 u16 tx_ba_win_size; 1101 u8 rx_ba_win_size;
1102 u8 tx_ba_win_size;
1099 u16 inactivity_timeout; 1103 u16 inactivity_timeout;
1104
1105 /* bitmap of enabled TIDs for TX BA sessions */
1106 u8 tx_ba_tid_bitmap;
1100}; 1107};
1101 1108
1102struct conf_memory_settings { 1109struct conf_memory_settings {
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 47d87aaa63a7..a374c2112be3 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -529,41 +529,24 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
529 return 0; 529 return 0;
530} 530}
531 531
532static void wl1271_check_ba_support(struct wl1271 *wl)
533{
534 /* validate FW cose ver x.x.x.50-60.x */
535 if ((wl->chip.fw_ver[3] >= WL12XX_BA_SUPPORT_FW_COST_VER2_START) &&
536 (wl->chip.fw_ver[3] < WL12XX_BA_SUPPORT_FW_COST_VER2_END)) {
537 wl->ba_support = true;
538 return;
539 }
540
541 wl->ba_support = false;
542}
543
544static int wl1271_set_ba_policies(struct wl1271 *wl) 532static int wl1271_set_ba_policies(struct wl1271 *wl)
545{ 533{
546 u8 tid_index;
547 int ret = 0;
548
549 /* Reset the BA RX indicators */ 534 /* Reset the BA RX indicators */
550 wl->ba_rx_bitmap = 0; 535 wl->ba_rx_bitmap = 0;
551 wl->ba_allowed = true; 536 wl->ba_allowed = true;
537 wl->ba_rx_session_count = 0;
552 538
553 /* validate that FW support BA */ 539 /* BA is supported in STA/AP modes */
554 wl1271_check_ba_support(wl); 540 if (wl->bss_type != BSS_TYPE_AP_BSS &&
541 wl->bss_type != BSS_TYPE_STA_BSS) {
542 wl->ba_support = false;
543 return 0;
544 }
555 545
556 if (wl->ba_support) 546 wl->ba_support = true;
557 /* 802.11n initiator BA session setting */
558 for (tid_index = 0; tid_index < CONF_TX_MAX_TID_COUNT;
559 ++tid_index) {
560 ret = wl1271_acx_set_ba_session(wl, WLAN_BACK_INITIATOR,
561 tid_index, true);
562 if (ret < 0)
563 break;
564 }
565 547
566 return ret; 548 /* 802.11n initiator BA session setting */
549 return wl12xx_acx_set_ba_initiator_policy(wl);
567} 550}
568 551
569int wl1271_chip_specific_init(struct wl1271 *wl) 552int wl1271_chip_specific_init(struct wl1271 *wl)
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index ea150b5ff9f5..934f5731fd73 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -286,8 +286,10 @@ static struct conf_drv_settings default_conf = {
286 }, 286 },
287 }, 287 },
288 .ht = { 288 .ht = {
289 .rx_ba_win_size = 8,
289 .tx_ba_win_size = 64, 290 .tx_ba_win_size = 64,
290 .inactivity_timeout = 10000, 291 .inactivity_timeout = 10000,
292 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
291 }, 293 },
292 .mem_wl127x = { 294 .mem_wl127x = {
293 .num_stations = 1, 295 .num_stations = 1,
@@ -3191,9 +3193,12 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3191 } 3193 }
3192 } 3194 }
3193 3195
3194 rcu_read_lock(); 3196 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3195 sta = ieee80211_find_sta(vif, bss_conf->bssid); 3197 rcu_read_lock();
3196 if (sta) { 3198 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3199 if (!sta)
3200 goto sta_not_found;
3201
3197 /* save the supp_rates of the ap */ 3202 /* save the supp_rates of the ap */
3198 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band]; 3203 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3199 if (sta->ht_cap.ht_supported) 3204 if (sta->ht_cap.ht_supported)
@@ -3201,38 +3206,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3201 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); 3206 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
3202 sta_ht_cap = sta->ht_cap; 3207 sta_ht_cap = sta->ht_cap;
3203 sta_exists = true; 3208 sta_exists = true;
3204 }
3205 rcu_read_unlock();
3206 3209
3207 if (sta_exists) { 3210sta_not_found:
3208 /* handle new association with HT and HT information change */ 3211 rcu_read_unlock();
3209 if ((changed & BSS_CHANGED_HT) &&
3210 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3211 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
3212 true);
3213 if (ret < 0) {
3214 wl1271_warning("Set ht cap true failed %d",
3215 ret);
3216 goto out;
3217 }
3218 ret = wl1271_acx_set_ht_information(wl,
3219 bss_conf->ht_operation_mode);
3220 if (ret < 0) {
3221 wl1271_warning("Set ht information failed %d",
3222 ret);
3223 goto out;
3224 }
3225 }
3226 /* handle new association without HT and disassociation */
3227 else if (changed & BSS_CHANGED_ASSOC) {
3228 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
3229 false);
3230 if (ret < 0) {
3231 wl1271_warning("Set ht cap false failed %d",
3232 ret);
3233 goto out;
3234 }
3235 }
3236 } 3212 }
3237 3213
3238 if ((changed & BSS_CHANGED_ASSOC)) { 3214 if ((changed & BSS_CHANGED_ASSOC)) {
@@ -3440,6 +3416,41 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3440 } 3416 }
3441 } 3417 }
3442 3418
3419 /* Handle new association with HT. Do this only after join. */
3420 if (sta_exists) {
3421 if ((changed & BSS_CHANGED_HT) &&
3422 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3423 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
3424 true);
3425 if (ret < 0) {
3426 wl1271_warning("Set ht cap true failed %d",
3427 ret);
3428 goto out;
3429 }
3430 }
3431 /* handle new association without HT and disassociation */
3432 else if (changed & BSS_CHANGED_ASSOC) {
3433 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
3434 false);
3435 if (ret < 0) {
3436 wl1271_warning("Set ht cap false failed %d",
3437 ret);
3438 goto out;
3439 }
3440 }
3441 }
3442
3443 /* Handle HT information change. Only after join. */
3444 if (sta_exists && (changed & BSS_CHANGED_HT) &&
3445 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3446 ret = wl1271_acx_set_ht_information(wl,
3447 bss_conf->ht_operation_mode);
3448 if (ret < 0) {
3449 wl1271_warning("Set ht information failed %d", ret);
3450 goto out;
3451 }
3452 }
3453
3443out: 3454out:
3444 return; 3455 return;
3445} 3456}
@@ -3623,6 +3634,7 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
3623 3634
3624 __clear_bit(id, wl->ap_hlid_map); 3635 __clear_bit(id, wl->ap_hlid_map);
3625 memset(wl->links[hlid].addr, 0, ETH_ALEN); 3636 memset(wl->links[hlid].addr, 0, ETH_ALEN);
3637 wl->links[hlid].ba_bitmap = 0;
3626 wl1271_tx_reset_link_queues(wl, hlid); 3638 wl1271_tx_reset_link_queues(wl, hlid);
3627 __clear_bit(hlid, &wl->ap_ps_map); 3639 __clear_bit(hlid, &wl->ap_ps_map);
3628 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); 3640 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
@@ -3725,6 +3737,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3725{ 3737{
3726 struct wl1271 *wl = hw->priv; 3738 struct wl1271 *wl = hw->priv;
3727 int ret; 3739 int ret;
3740 u8 hlid, *ba_bitmap;
3741
3742 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
3743 tid);
3744
3745 /* sanity check - the fields in FW are only 8bits wide */
3746 if (WARN_ON(tid > 0xFF))
3747 return -ENOTSUPP;
3728 3748
3729 mutex_lock(&wl->mutex); 3749 mutex_lock(&wl->mutex);
3730 3750
@@ -3733,6 +3753,20 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3733 goto out; 3753 goto out;
3734 } 3754 }
3735 3755
3756 if (wl->bss_type == BSS_TYPE_STA_BSS) {
3757 hlid = wl->sta_hlid;
3758 ba_bitmap = &wl->ba_rx_bitmap;
3759 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
3760 struct wl1271_station *wl_sta;
3761
3762 wl_sta = (struct wl1271_station *)sta->drv_priv;
3763 hlid = wl_sta->hlid;
3764 ba_bitmap = &wl->links[hlid].ba_bitmap;
3765 } else {
3766 ret = -EINVAL;
3767 goto out;
3768 }
3769
3736 ret = wl1271_ps_elp_wakeup(wl); 3770 ret = wl1271_ps_elp_wakeup(wl);
3737 if (ret < 0) 3771 if (ret < 0)
3738 goto out; 3772 goto out;
@@ -3742,20 +3776,46 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3742 3776
3743 switch (action) { 3777 switch (action) {
3744 case IEEE80211_AMPDU_RX_START: 3778 case IEEE80211_AMPDU_RX_START:
3745 if ((wl->ba_support) && (wl->ba_allowed)) { 3779 if (!wl->ba_support || !wl->ba_allowed) {
3746 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3747 true);
3748 if (!ret)
3749 wl->ba_rx_bitmap |= BIT(tid);
3750 } else {
3751 ret = -ENOTSUPP; 3780 ret = -ENOTSUPP;
3781 break;
3782 }
3783
3784 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
3785 ret = -EBUSY;
3786 wl1271_error("exceeded max RX BA sessions");
3787 break;
3788 }
3789
3790 if (*ba_bitmap & BIT(tid)) {
3791 ret = -EINVAL;
3792 wl1271_error("cannot enable RX BA session on active "
3793 "tid: %d", tid);
3794 break;
3795 }
3796
3797 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
3798 hlid);
3799 if (!ret) {
3800 *ba_bitmap |= BIT(tid);
3801 wl->ba_rx_session_count++;
3752 } 3802 }
3753 break; 3803 break;
3754 3804
3755 case IEEE80211_AMPDU_RX_STOP: 3805 case IEEE80211_AMPDU_RX_STOP:
3756 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false); 3806 if (!(*ba_bitmap & BIT(tid))) {
3757 if (!ret) 3807 ret = -EINVAL;
3758 wl->ba_rx_bitmap &= ~BIT(tid); 3808 wl1271_error("no active RX BA session on tid: %d",
3809 tid);
3810 break;
3811 }
3812
3813 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
3814 hlid);
3815 if (!ret) {
3816 *ba_bitmap &= ~BIT(tid);
3817 wl->ba_rx_session_count--;
3818 }
3759 break; 3819 break;
3760 3820
3761 /* 3821 /*
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 1313dc5b855e..487c3c7e0273 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -355,6 +355,9 @@ struct wl1271_link {
355 u8 prev_freed_blks; 355 u8 prev_freed_blks;
356 356
357 u8 addr[ETH_ALEN]; 357 u8 addr[ETH_ALEN];
358
359 /* bitmap of TIDs where RX BA sessions are active for this link */
360 u8 ba_bitmap;
358}; 361};
359 362
360struct wl1271 { 363struct wl1271 {
@@ -609,6 +612,9 @@ struct wl1271 {
609 612
610 /* Platform limitations */ 613 /* Platform limitations */
611 unsigned int platform_quirks; 614 unsigned int platform_quirks;
615
616 /* number of currently active RX BA sessions */
617 int ba_rx_session_count;
612}; 618};
613 619
614struct wl1271_station { 620struct wl1271_station {