diff options
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/rx_reorder.c')
| -rw-r--r-- | drivers/net/wireless/ath/wil6210/rx_reorder.c | 146 |
1 files changed, 72 insertions, 74 deletions
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index a43cffcf1bbf..d385bc03033a 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #include "wil6210.h" @@ -40,11 +30,10 @@ static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq) return seq_sub(seq, r->ssn) % r->buf_size; } -static void wil_release_reorder_frame(struct wil6210_priv *wil, +static void wil_release_reorder_frame(struct net_device *ndev, struct wil_tid_ampdu_rx *r, int index) { - struct net_device *ndev = wil_to_ndev(wil); struct sk_buff *skb = r->reorder_buf[index]; if (!skb) @@ -59,7 +48,7 @@ no_frame: r->head_seq_num = seq_inc(r->head_seq_num); } -static void wil_release_reorder_frames(struct wil6210_priv *wil, +static void wil_release_reorder_frames(struct net_device *ndev, struct wil_tid_ampdu_rx *r, u16 hseq) { @@ -73,18 +62,18 @@ static void wil_release_reorder_frames(struct wil6210_priv *wil, */ while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) { index = reorder_index(r, r->head_seq_num); - wil_release_reorder_frame(wil, r, index); + wil_release_reorder_frame(ndev, r, index); } r->head_seq_num = hseq; } -static void wil_reorder_release(struct wil6210_priv *wil, +static void 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(wil, r, index); + wil_release_reorder_frame(ndev, r, index); index = reorder_index(r, r->head_seq_num); } } @@ -93,25 +82,29 @@ static void wil_reorder_release(struct wil6210_priv *wil, void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { - struct net_device *ndev = wil_to_ndev(wil); - struct vring_rx_desc *d = wil_skb_rxdesc(skb); - int tid = wil_rxdesc_tid(d); - int cid = wil_rxdesc_cid(d); - int mid = wil_rxdesc_mid(d); - u16 seq = wil_rxdesc_seq(d); - int mcast = wil_rxdesc_mcast(d); - struct wil_sta_info *sta = &wil->sta[cid]; + 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; + wil->txrx_ops.get_reorder_params(wil, skb, &tid, &cid, &mid, &seq, + &mcast, &retry); + sta = &wil->sta[cid]; + wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n", mid, cid, tid, seq, mcast); - if (unlikely(mcast)) { - wil_netif_rx_any(skb, ndev); + vif = wil->vifs[mid]; + if (unlikely(!vif)) { + wil_dbg_txrx(wil, "invalid VIF, mid %d\n", mid); + dev_kfree_skb(skb); return; } + ndev = vif_to_ndev(vif); spin_lock(&sta->tid_rx_lock); @@ -121,6 +114,19 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) goto out; } + if (unlikely(mcast)) { + if (retry && seq == r->mcast_last_seq) { + r->drop_dup_mcast++; + wil_dbg_txrx(wil, "Rx drop: dup mcast seq 0x%03x\n", + seq); + dev_kfree_skb(skb); + goto out; + } + r->mcast_last_seq = seq; + wil_netif_rx_any(skb, ndev); + goto out; + } + r->total++; hseq = r->head_seq_num; @@ -168,7 +174,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) 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(wil, r, hseq); + wil_release_reorder_frames(ndev, r, hseq); } /* Now the new frame is always in the range of the reordering buffer */ @@ -197,18 +203,19 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) /* put the frame in the reordering buffer */ r->reorder_buf[index] = skb; - r->reorder_time[index] = jiffies; r->stored_mpdu_num++; - wil_reorder_release(wil, r); + 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, u8 cid, u8 tid, u16 seq) +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); @@ -223,9 +230,9 @@ void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq) seq, r->head_seq_num); goto out; } - wil_dbg_txrx(wil, "BAR: CID %d TID %d Seq 0x%03x head 0x%03x\n", - cid, tid, seq, r->head_seq_num); - wil_release_reorder_frames(wil, r, seq); + 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); out: spin_unlock(&sta->tid_rx_lock); @@ -241,11 +248,7 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, r->reorder_buf = kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL); - r->reorder_time = - kcalloc(size, sizeof(unsigned long), GFP_KERNEL); - if (!r->reorder_buf || !r->reorder_time) { - kfree(r->reorder_buf); - kfree(r->reorder_time); + if (!r->reorder_buf) { kfree(r); return NULL; } @@ -255,6 +258,7 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, r->buf_size = size; r->stored_mpdu_num = 0; r->first_time = true; + r->mcast_last_seq = U16_MAX; return r; } @@ -275,14 +279,13 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, kfree_skb(r->reorder_buf[i]); kfree(r->reorder_buf); - kfree(r->reorder_time); kfree(r); } /* ADDBA processing */ static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize) { - u16 max_agg_size = min_t(u16, WIL_MAX_AGG_WSIZE, WIL_MAX_AMPDU_SIZE / + u16 max_agg_size = min_t(u16, wil->max_agg_wsize, wil->max_ampdu_size / (mtu_max + WIL_MAX_MPDU_OVERHEAD)); if (!req_agg_wsize) @@ -292,7 +295,7 @@ static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize) } /* Block Ack - Rx side (recipient) */ -int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, +int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid, u8 dialog_token, __le16 ba_param_set, __le16 ba_timeout, __le16 ba_seq_ctrl) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) @@ -301,26 +304,26 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) u16 agg_timeout = le16_to_cpu(ba_timeout); u16 seq_ctrl = le16_to_cpu(ba_seq_ctrl); struct wil_sta_info *sta; - u8 cid, tid; - u16 agg_wsize = 0; + u16 agg_wsize; /* bit 0: A-MSDU supported * bit 1: policy (should be 0 for us) * bits 2..5: TID * bits 6..15: buffer size */ u16 req_agg_wsize = WIL_GET_BITS(param_set, 6, 15); - bool agg_amsdu = !!(param_set & BIT(0)); + bool agg_amsdu = wil->use_enhanced_dma_hw && + wil->use_rx_hw_reordering && + test_bit(WMI_FW_CAPABILITY_AMSDU, wil->fw_capabilities) && + wil->amsdu_en && (param_set & BIT(0)); int ba_policy = param_set & BIT(1); - u16 status = WLAN_STATUS_SUCCESS; u16 ssn = seq_ctrl >> 4; struct wil_tid_ampdu_rx *r; int rc = 0; might_sleep(); - parse_cidxtid(cidxtid, &cid, &tid); /* sanity checks */ - if (cid >= WIL6210_MAX_CID) { + if (cid >= wil->max_assoc_sta) { wil_err(wil, "BACK: invalid CID %d\n", cid); rc = -EINVAL; goto out; @@ -339,35 +342,30 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) agg_amsdu ? "+" : "-", !!ba_policy, dialog_token, ssn); /* apply policies */ - if (ba_policy) { - wil_err(wil, "BACK requested unsupported ba_policy == 1\n"); - status = WLAN_STATUS_INVALID_QOS_PARAM; - } - if (status == WLAN_STATUS_SUCCESS) { - if (req_agg_wsize == 0) { - wil_dbg_misc(wil, "Suggest BACK wsize %d\n", - WIL_MAX_AGG_WSIZE); - agg_wsize = WIL_MAX_AGG_WSIZE; - } else { - agg_wsize = min_t(u16, - WIL_MAX_AGG_WSIZE, req_agg_wsize); - } + if (req_agg_wsize == 0) { + wil_dbg_misc(wil, "Suggest BACK wsize %d\n", + wil->max_agg_wsize); + agg_wsize = wil->max_agg_wsize; + } else { + agg_wsize = min_t(u16, wil->max_agg_wsize, req_agg_wsize); } - rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status, - agg_amsdu, agg_wsize, agg_timeout); - if (rc || (status != WLAN_STATUS_SUCCESS)) { - wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc, - status); + rc = wil->txrx_ops.wmi_addba_rx_resp(wil, mid, cid, tid, dialog_token, + WLAN_STATUS_SUCCESS, agg_amsdu, + agg_wsize, agg_timeout); + if (rc) { + wil_err(wil, "do not apply ba, rc(%d)\n", rc); goto out; } /* apply */ - r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); - spin_lock_bh(&sta->tid_rx_lock); - wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); - sta->tid_rx[tid] = r; - spin_unlock_bh(&sta->tid_rx_lock); + if (!wil->use_rx_hw_reordering) { + r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); + spin_lock_bh(&sta->tid_rx_lock); + wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); + sta->tid_rx[tid] = r; + spin_unlock_bh(&sta->tid_rx_lock); + } out: return rc; @@ -378,7 +376,7 @@ int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize) { u8 agg_wsize = wil_agg_size(wil, wsize); u16 agg_timeout = 0; - struct vring_tx_data *txdata = &wil->vring_tx_data[ringid]; + struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ringid]; int rc = 0; if (txdata->addba_in_progress) { @@ -393,7 +391,7 @@ int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize) goto out; } txdata->addba_in_progress = true; - rc = wmi_addba(wil, ringid, agg_wsize, agg_timeout); + rc = wmi_addba(wil, txdata->mid, ringid, agg_wsize, agg_timeout); if (rc) { wil_err(wil, "wmi_addba failed, rc (%d)", rc); txdata->addba_in_progress = false; |
