diff options
author | Janusz Dziedzic <janusz.dziedzic@tieto.com> | 2014-07-25 04:28:50 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2014-07-25 04:51:07 -0400 |
commit | 0ccb7a3485e5526dca69f036b0d6c5148c78b3f8 (patch) | |
tree | 536e109456e6f5b4acaa7faf5edebb1f3d5a31b2 /drivers/net | |
parent | cf850d1d23942ad7fb3c22cb848decec86c101b0 (diff) |
ath10k: handle attention flags correctly when using A-MSDU
In case of A-MSDU RX we should check attention flags
correctly to be sure we report correct FCS status for
A-MSDU subframes. Without a patch we could report A-MSDU
subframes with wrong FCS as a correct to the stack, next
get a lot of DUP ACK TCP packets. Finally TP drop is seen
and this drop depends on FCS errors ratio for A-MSDU frame.
Example test case when TP drop is seen:
- ath10k configured as an AP
- used ath10k station
- forced A-MSDU (7 frames) on STA
- other traffic on channel (often FCS errors)
- monitor iface added on AP
- TCP STA -> AP traffic (iperf)
a) Iperf logs for case without the patch:
echo "1 64" > htt_max_amsdu_ampdu // disable A-MSDU
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 5.0 sec 56.6 MBytes 95.0 Mbits/sec
[ 3] 5.0-10.0 sec 60.4 MBytes 101 Mbits/sec
[ 3] 10.0-15.0 sec 60.2 MBytes 101 Mbits/sec
[ 3] 15.0-20.0 sec 60.2 MBytes 101 Mbits/sec
[ 3] 20.0-25.0 sec 63.8 MBytes 107 Mbits/sec
[ 3] 25.0-30.0 sec 64.9 MBytes 109 Mbits/sec
echo "7 64" > htt_max_amsdu_ampdu // set 7 A-MSDU subframes
[ 3] 30.0-35.0 sec 40.0 MBytes 67.1 Mbits/sec
[ 3] 35.0-40.0 sec 35.9 MBytes 60.2 Mbits/sec
[ 3] 40.0-45.0 sec 36.9 MBytes 61.9 Mbits/sec
[ 3] 45.0-50.0 sec 37.9 MBytes 63.5 Mbits/sec
[ 3] 50.0-55.0 sec 34.5 MBytes 57.9 Mbits/sec
[ 3] 55.0-60.0 sec 25.4 MBytes 42.6 Mbits/sec
[ 3] 60.0-65.0 sec 48.2 MBytes 81.0 Mbits/sec
[ 3] 65.0-70.0 sec 28.8 MBytes 48.2 Mbits/sec
[ 3] 70.0-75.0 sec 29.2 MBytes 49.1 Mbits/sec
[ 3] 75.0-80.0 sec 22.9 MBytes 38.4 Mbits/sec
[ 3] 80.0-85.0 sec 26.4 MBytes 44.2 Mbits/sec
[ 3] 85.0-90.0 sec 31.5 MBytes 52.8 Mbits/sec
b) Iperf logs for case with patch:
echo "1 64" > htt_max_amsdu_ampdu // disable A-MSDU
[ 3] local 192.168.12.2 port 57512 connected with 192.168.12.1 port 5001
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 5.0 sec 60.8 MBytes 102 Mbits/sec
[ 3] 5.0-10.0 sec 62.2 MBytes 104 Mbits/sec
[ 3] 10.0-15.0 sec 60.9 MBytes 102 Mbits/sec
echo "7 64" > htt_max_amsdu_ampdu // set 7 A-MSDU subframes
[ 3] 15.0-20.0 sec 68.1 MBytes 114 Mbits/sec
[ 3] 20.0-25.0 sec 80.5 MBytes 135 Mbits/sec
[ 3] 25.0-30.0 sec 83.0 MBytes 139 Mbits/sec
[ 3] 30.0-35.0 sec 79.1 MBytes 133 Mbits/sec
[ 3] 35.0-40.0 sec 77.1 MBytes 129 Mbits/sec
[ 3] 40.0-45.0 sec 77.4 MBytes 130 Mbits/sec
Reported-by: Denton Gentry <denton.gentry@gmail.com>
Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt_rx.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 77cdc21e28d7..80cdac15588a 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c | |||
@@ -308,7 +308,8 @@ static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb) | |||
308 | static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, | 308 | static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, |
309 | u8 **fw_desc, int *fw_desc_len, | 309 | u8 **fw_desc, int *fw_desc_len, |
310 | struct sk_buff **head_msdu, | 310 | struct sk_buff **head_msdu, |
311 | struct sk_buff **tail_msdu) | 311 | struct sk_buff **tail_msdu, |
312 | u32 *attention) | ||
312 | { | 313 | { |
313 | int msdu_len, msdu_chaining = 0; | 314 | int msdu_len, msdu_chaining = 0; |
314 | struct sk_buff *msdu; | 315 | struct sk_buff *msdu; |
@@ -358,6 +359,11 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, | |||
358 | break; | 359 | break; |
359 | } | 360 | } |
360 | 361 | ||
362 | *attention |= __le32_to_cpu(rx_desc->attention.flags) & | ||
363 | (RX_ATTENTION_FLAGS_TKIP_MIC_ERR | | ||
364 | RX_ATTENTION_FLAGS_DECRYPT_ERR | | ||
365 | RX_ATTENTION_FLAGS_FCS_ERR | | ||
366 | RX_ATTENTION_FLAGS_MGMT_TYPE); | ||
361 | /* | 367 | /* |
362 | * Copy the FW rx descriptor for this MSDU from the rx | 368 | * Copy the FW rx descriptor for this MSDU from the rx |
363 | * indication message into the MSDU's netbuf. HL uses the | 369 | * indication message into the MSDU's netbuf. HL uses the |
@@ -1216,13 +1222,15 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, | |||
1216 | for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) { | 1222 | for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) { |
1217 | struct sk_buff *msdu_head, *msdu_tail; | 1223 | struct sk_buff *msdu_head, *msdu_tail; |
1218 | 1224 | ||
1225 | attention = 0; | ||
1219 | msdu_head = NULL; | 1226 | msdu_head = NULL; |
1220 | msdu_tail = NULL; | 1227 | msdu_tail = NULL; |
1221 | ret = ath10k_htt_rx_amsdu_pop(htt, | 1228 | ret = ath10k_htt_rx_amsdu_pop(htt, |
1222 | &fw_desc, | 1229 | &fw_desc, |
1223 | &fw_desc_len, | 1230 | &fw_desc_len, |
1224 | &msdu_head, | 1231 | &msdu_head, |
1225 | &msdu_tail); | 1232 | &msdu_tail, |
1233 | &attention); | ||
1226 | 1234 | ||
1227 | if (ret < 0) { | 1235 | if (ret < 0) { |
1228 | ath10k_warn("failed to pop amsdu from htt rx ring %d\n", | 1236 | ath10k_warn("failed to pop amsdu from htt rx ring %d\n", |
@@ -1234,7 +1242,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, | |||
1234 | rxd = container_of((void *)msdu_head->data, | 1242 | rxd = container_of((void *)msdu_head->data, |
1235 | struct htt_rx_desc, | 1243 | struct htt_rx_desc, |
1236 | msdu_payload); | 1244 | msdu_payload); |
1237 | attention = __le32_to_cpu(rxd->attention.flags); | ||
1238 | 1245 | ||
1239 | if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, | 1246 | if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, |
1240 | status, | 1247 | status, |
@@ -1287,6 +1294,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, | |||
1287 | u8 *fw_desc; | 1294 | u8 *fw_desc; |
1288 | int fw_desc_len, hdrlen, paramlen; | 1295 | int fw_desc_len, hdrlen, paramlen; |
1289 | int trim; | 1296 | int trim; |
1297 | u32 attention = 0; | ||
1290 | 1298 | ||
1291 | fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes); | 1299 | fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes); |
1292 | fw_desc = (u8 *)frag->fw_msdu_rx_desc; | 1300 | fw_desc = (u8 *)frag->fw_msdu_rx_desc; |
@@ -1296,7 +1304,8 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, | |||
1296 | 1304 | ||
1297 | spin_lock_bh(&htt->rx_ring.lock); | 1305 | spin_lock_bh(&htt->rx_ring.lock); |
1298 | ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, | 1306 | ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, |
1299 | &msdu_head, &msdu_tail); | 1307 | &msdu_head, &msdu_tail, |
1308 | &attention); | ||
1300 | spin_unlock_bh(&htt->rx_ring.lock); | 1309 | spin_unlock_bh(&htt->rx_ring.lock); |
1301 | 1310 | ||
1302 | ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); | 1311 | ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); |
@@ -1313,10 +1322,8 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, | |||
1313 | 1322 | ||
1314 | hdr = (struct ieee80211_hdr *)msdu_head->data; | 1323 | hdr = (struct ieee80211_hdr *)msdu_head->data; |
1315 | rxd = (void *)msdu_head->data - sizeof(*rxd); | 1324 | rxd = (void *)msdu_head->data - sizeof(*rxd); |
1316 | tkip_mic_err = !!(__le32_to_cpu(rxd->attention.flags) & | 1325 | tkip_mic_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR); |
1317 | RX_ATTENTION_FLAGS_TKIP_MIC_ERR); | 1326 | decrypt_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR); |
1318 | decrypt_err = !!(__le32_to_cpu(rxd->attention.flags) & | ||
1319 | RX_ATTENTION_FLAGS_DECRYPT_ERR); | ||
1320 | fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), | 1327 | fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), |
1321 | RX_MSDU_START_INFO1_DECAP_FORMAT); | 1328 | RX_MSDU_START_INFO1_DECAP_FORMAT); |
1322 | 1329 | ||