diff options
author | Arik Nemtsov <arik@wizery.com> | 2011-08-17 03:45:49 -0400 |
---|---|---|
committer | Luciano Coelho <coelho@ti.com> | 2011-08-22 05:35:27 -0400 |
commit | 0f9c8250e10a16f48f82ffda3a5a7cb9e7b4a9ee (patch) | |
tree | 32762d2ec797422fd152d4a7bc3c920104a47808 /drivers/net/wireless/wl12xx | |
parent | e51ae9be2e313b63a43f1f93578d9a71d38a77ea (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.c | 66 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/acx.h | 82 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/cmd.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/conf.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/init.c | 37 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 146 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl12xx.h | 6 |
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. */ |
1395 | int wl1271_acx_set_ba_session(struct wl1271 *wl, | 1391 | int 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. */ |
1446 | int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, | 1425 | int 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 { | |||
907 | struct wl1271_acx_ht_capabilities { | 911 | struct 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 | ||
984 | struct wl1271_acx_ba_session_policy { | 967 | struct 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 | ||
1016 | struct wl1271_acx_ba_receiver_setup { | 990 | struct 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 | ||
1035 | struct wl1271_acx_fw_tsf_information { | 1009 | struct 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); |
1298 | int wl1271_acx_set_ht_information(struct wl1271 *wl, | 1272 | int wl1271_acx_set_ht_information(struct wl1271 *wl, |
1299 | u16 ht_operation_mode); | 1273 | u16 ht_operation_mode); |
1300 | int wl1271_acx_set_ba_session(struct wl1271 *wl, | 1274 | int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl); |
1301 | enum ieee80211_back_parties direction, | 1275 | int 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); |
1303 | int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, | ||
1304 | bool enable); | ||
1305 | int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); | 1277 | int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); |
1306 | int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable); | 1278 | int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable); |
1307 | int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); | 1279 | int 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 | |||
560 | enum { | 563 | enum { |
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 | ||
1097 | struct conf_ht_setting { | 1100 | struct 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 | ||
1102 | struct conf_memory_settings { | 1109 | struct 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 | ||
532 | static 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 | |||
544 | static int wl1271_set_ba_policies(struct wl1271 *wl) | 532 | static 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 | ||
569 | int wl1271_chip_specific_init(struct wl1271 *wl) | 552 | int 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) { | 3210 | sta_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 | |||
3443 | out: | 3454 | out: |
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 | ||
360 | struct wl1271 { | 363 | struct 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 | ||
614 | struct wl1271_station { | 620 | struct wl1271_station { |