When starting an offloaded BA session it is unknown what starting sequence number should be used. Using last_seq worked in most cases except after hw restart. When hw restart is requested last_seq is (rightfully so) kept unmodified. This ended up with BA sessions being restarted with an aribtrary BA window values resulting in dropped frames until sequence numbers caught up. Instead of last_seq pick seqno of a first Rxed frame of a given BA session. This fixes stalled traffic after hw restart with offloaded BA sessions (currently only ath10k).
Unified · Split
| @@ -227,7 +227,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d · 226 unmodified lines | ||
| 227 | 227 | void __ieee80211_start_rx_ba_session(struct sta_info *sta, |
| 228 | 228 | u8 dialog_token, u16 timeout, |
| 229 | 229 | u16 start_seq_num, u16 ba_policy, u16 tid, |
| 230 | − u16 buf_size, bool tx) | |
| 230 | + u16 buf_size, bool tx, bool auto_seq) | |
| 231 | 231 | { |
| 232 | 232 | struct ieee80211_local *local = sta->sdata->local; |
| 233 | 233 | struct tid_ampdu_rx *tid_agg_rx; |
| @@ -326,6 +326,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, · 92 unmodified lines | ||
| 326 | 326 | tid_agg_rx->buf_size = buf_size; |
| 327 | 327 | tid_agg_rx->timeout = timeout; |
| 328 | 328 | tid_agg_rx->stored_mpdu_num = 0; |
| 329 | + tid_agg_rx->auto_seq = auto_seq; | |
| 329 | 330 | status = WLAN_STATUS_SUCCESS; |
| 330 | 331 | |
| 331 | 332 | /* activate it for RX */ |
| @@ -367,7 +368,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, · 35 unmodified lines | ||
| 367 | 368 | |
| 368 | 369 | __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, |
| 369 | 370 | start_seq_num, ba_policy, tid, |
| 370 | − buf_size, true); | |
| 371 | + buf_size, true, false); | |
| 371 | 372 | } |
| 372 | 373 | |
| 373 | 374 | void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif, |
| @@ -1587,7 +1587,7 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, · 1586 unmodified lines | ||
| 1587 | 1587 | void __ieee80211_start_rx_ba_session(struct sta_info *sta, |
| 1588 | 1588 | u8 dialog_token, u16 timeout, |
| 1589 | 1589 | u16 start_seq_num, u16 ba_policy, u16 tid, |
| 1590 | − u16 buf_size, bool tx); | |
| 1590 | + u16 buf_size, bool tx, bool auto_seq); | |
| 1591 | 1591 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, |
| 1592 | 1592 | enum ieee80211_agg_stop_reason reason); |
| 1593 | 1593 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, |
| @@ -1172,19 +1172,11 @@ static void ieee80211_iface_work(struct work_struct *work) · 1171 unmodified lines | ||
| 1172 | 1172 | rx_agg = (void *)&skb->cb; |
| 1173 | 1173 | mutex_lock(&local->sta_mtx); |
| 1174 | 1174 | sta = sta_info_get_bss(sdata, rx_agg->addr); |
| 1175 | − if (sta) { | |
| 1176 | − u16 last_seq; | |
| 1177 | − | |
| 1178 | − last_seq = le16_to_cpu( | |
| 1179 | − sta->last_seq_ctrl[rx_agg->tid]); | |
| 1180 | − | |
| 1175 | + if (sta) | |
| 1181 | 1176 | __ieee80211_start_rx_ba_session(sta, |
| 1182 | − 0, 0, | |
| 1183 | − ieee80211_sn_inc(last_seq), | |
| 1184 | − 1, rx_agg->tid, | |
| 1177 | + 0, 0, 0, 1, rx_agg->tid, | |
| 1185 | 1178 | IEEE80211_MAX_AMPDU_BUF, |
| 1186 | − false); | |
| 1187 | − } | |
| 1179 | + false, true); | |
| 1188 | 1180 | mutex_unlock(&local->sta_mtx); |
| 1189 | 1181 | } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_STOP) { |
| 1190 | 1182 | rx_agg = (void *)&skb->cb; |
| @@ -835,6 +835,16 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata · 834 unmodified lines | ||
| 835 | 835 | |
| 836 | 836 | spin_lock(&tid_agg_rx->reorder_lock); |
| 837 | 837 | |
| 838 | + /* | |
| 839 | + * Offloaded BA sessions have no known starting sequence number so pick | |
| 840 | + * one from first Rxed frame for this tid after BA was started. | |
| 841 | + */ | |
| 842 | + if (unlikely(tid_agg_rx->auto_seq)) { | |
| 843 | + tid_agg_rx->auto_seq = false; | |
| 844 | + tid_agg_rx->ssn = mpdu_seq_num; | |
| 845 | + tid_agg_rx->head_seq_num = mpdu_seq_num; | |
| 846 | + } | |
| 847 | + | |
| 838 | 848 | buf_size = tid_agg_rx->buf_size; |
| 839 | 849 | head_seq_num = tid_agg_rx->head_seq_num; |
| 840 | 850 | |
| @@ -167,6 +167,8 @@ struct tid_ampdu_tx { · 166 unmodified lines | ||
| 167 | 167 | * @dialog_token: dialog token for aggregation session |
| 168 | 168 | * @rcu_head: RCU head used for freeing this struct |
| 169 | 169 | * @reorder_lock: serializes access to reorder buffer, see below. |
| 170 | + * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and | |
| 171 | + * and ssn. | |
| 170 | 172 | * |
| 171 | 173 | * This structure's lifetime is managed by RCU, assignments to |
| 172 | 174 | * the array holding it must hold the aggregation mutex. |
| @@ -190,6 +192,7 @@ struct tid_ampdu_rx { · 17 unmodified lines | ||
| 190 | 192 | u16 buf_size; |
| 191 | 193 | u16 timeout; |
| 192 | 194 | u8 dialog_token; |
| 195 | + bool auto_seq; | |
| 193 | 196 | }; |
| 194 | 197 | |
| 195 | 198 | /** |