// SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
/* note: this function is never called with * hseq preceding r->head_seq_num, i.e it is always true * !seq_less(hseq, r->head_seq_num) * and thus on loop exit it should be * r->head_seq_num == hseq
*/ while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) {
index = reorder_index(r, r->head_seq_num);
wil_release_reorder_frame(ndev, r, index);
}
r->head_seq_num = hseq;
}
staticvoid wil_reorder_release(struct net_device *ndev, struct wil_tid_ampdu_rx *r)
{ int index = reorder_index(r, r->head_seq_num);
while (r->reorder_buf[index]) {
wil_release_reorder_frame(ndev, r, index);
index = reorder_index(r, r->head_seq_num);
}
}
/* called in NAPI context */ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{ struct wil6210_vif *vif; struct net_device *ndev; int tid, cid, mid, mcast, retry;
u16 seq; struct wil_sta_info *sta; struct wil_tid_ampdu_rx *r;
u16 hseq; int index;
/** Due to the race between WMI events, where BACK establishment * reported, and data Rx, few packets may be pass up before reorder * buffer get allocated. Catch up by pretending SSN is what we * see in the 1-st Rx packet * * Another scenario, Rx get delayed and we got packet from before * BACK. Pass it to the stack and wait.
*/ if (r->first_time) {
r->first_time = false; if (seq != r->head_seq_num) { if (seq_less(seq, r->head_seq_num)) {
wil_err(wil, "Error: frame with early sequence 0x%03x, should be 0x%03x. Waiting...\n",
seq, r->head_seq_num);
r->first_time = true;
wil_netif_rx_any(skb, ndev); goto out;
}
wil_err(wil, "Error: 1-st frame with wrong sequence 0x%03x, should be 0x%03x. Fixing...\n",
seq, r->head_seq_num);
r->head_seq_num = seq;
r->ssn = seq;
}
}
/* frame with out of date sequence number */ if (seq_less(seq, r->head_seq_num)) {
r->ssn_last_drop = seq;
r->drop_old++;
wil_dbg_txrx(wil, "Rx drop: old seq 0x%03x head 0x%03x\n",
seq, r->head_seq_num);
dev_kfree_skb(skb); goto out;
}
/* * If frame the sequence number exceeds our buffering window * size release some previous frames to make room for this one.
*/ if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
hseq = seq_inc(seq_sub(seq, r->buf_size)); /* release stored frames up to new head to stack */
wil_release_reorder_frames(ndev, r, hseq);
}
/* Now the new frame is always in the range of the reordering buffer */
index = reorder_index(r, seq);
/* check if we already stored this frame */ if (r->reorder_buf[index]) {
r->drop_dup++;
wil_dbg_txrx(wil, "Rx drop: dup seq 0x%03x\n", seq);
dev_kfree_skb(skb); goto out;
}
/* * If the current MPDU is in the right order and nothing else * is stored we can process it directly, no need to buffer it. * If it is first but there's something stored, we may be able * to release frames after this one.
*/ if (seq == r->head_seq_num && r->stored_mpdu_num == 0) {
r->head_seq_num = seq_inc(r->head_seq_num);
wil_netif_rx_any(skb, ndev); goto out;
}
/* put the frame in the reordering buffer */
r->reorder_buf[index] = skb;
r->stored_mpdu_num++;
wil_reorder_release(ndev, r);
out:
spin_unlock(&sta->tid_rx_lock);
}
/* process BAR frame, called in NAPI context */ void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif,
u8 cid, u8 tid, u16 seq)
{ struct wil_sta_info *sta = &wil->sta[cid]; struct net_device *ndev = vif_to_ndev(vif); struct wil_tid_ampdu_rx *r;
spin_lock(&sta->tid_rx_lock);
r = sta->tid_rx[tid]; if (!r) {
wil_err(wil, "BAR for non-existing CID %d TID %d\n", cid, tid); goto out;
} if (seq_less(seq, r->head_seq_num)) {
wil_err(wil, "BAR Seq 0x%03x preceding head 0x%03x\n",
seq, r->head_seq_num); goto out;
}
wil_dbg_txrx(wil, "BAR: CID %d MID %d TID %d Seq 0x%03x head 0x%03x\n",
cid, vif->mid, tid, seq, r->head_seq_num);
wil_release_reorder_frames(ndev, r, seq);
void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, struct wil_tid_ampdu_rx *r)
{ int i;
if (!r) return;
/* Do not pass remaining frames to the network stack - it may be * not expecting to get any more Rx. Rx from here may lead to * kernel OOPS since some per-socket accounting info was already * released.
*/ for (i = 0; i < r->buf_size; i++)
kfree_skb(r->reorder_buf[i]);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.