| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: ISC |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name> |
|---|
| 3 | | - * |
|---|
| 4 | | - * Permission to use, copy, modify, and/or distribute this software for any |
|---|
| 5 | | - * purpose with or without fee is hereby granted, provided that the above |
|---|
| 6 | | - * copyright notice and this permission notice appear in all copies. |
|---|
| 7 | | - * |
|---|
| 8 | | - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|---|
| 9 | | - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|---|
| 10 | | - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|---|
| 11 | | - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|---|
| 12 | | - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|---|
| 13 | | - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|---|
| 14 | | - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|---|
| 15 | 4 | */ |
|---|
| 16 | 5 | #include "mt76.h" |
|---|
| 17 | 6 | |
|---|
| 18 | | -#define REORDER_TIMEOUT (HZ / 10) |
|---|
| 7 | +static unsigned long mt76_aggr_tid_to_timeo(u8 tidno) |
|---|
| 8 | +{ |
|---|
| 9 | + /* Currently voice traffic (AC_VO) always runs without aggregation, |
|---|
| 10 | + * no special handling is needed. AC_BE/AC_BK use tids 0-3. Just check |
|---|
| 11 | + * for non AC_BK/AC_BE and set smaller timeout for it. */ |
|---|
| 12 | + return HZ / (tidno >= 4 ? 25 : 10); |
|---|
| 13 | +} |
|---|
| 19 | 14 | |
|---|
| 20 | 15 | static void |
|---|
| 21 | 16 | mt76_aggr_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames, int idx) |
|---|
| .. | .. |
|---|
| 34 | 29 | } |
|---|
| 35 | 30 | |
|---|
| 36 | 31 | static void |
|---|
| 37 | | -mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid, struct sk_buff_head *frames, |
|---|
| 38 | | - u16 head) |
|---|
| 32 | +mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid, |
|---|
| 33 | + struct sk_buff_head *frames, |
|---|
| 34 | + u16 head) |
|---|
| 39 | 35 | { |
|---|
| 40 | 36 | int idx; |
|---|
| 41 | 37 | |
|---|
| .. | .. |
|---|
| 74 | 70 | for (idx = (tid->head + 1) % tid->size; |
|---|
| 75 | 71 | idx != start && nframes; |
|---|
| 76 | 72 | idx = (idx + 1) % tid->size) { |
|---|
| 77 | | - |
|---|
| 78 | 73 | skb = tid->reorder_buf[idx]; |
|---|
| 79 | 74 | if (!skb) |
|---|
| 80 | 75 | continue; |
|---|
| 81 | 76 | |
|---|
| 82 | 77 | nframes--; |
|---|
| 83 | | - status = (struct mt76_rx_status *) skb->cb; |
|---|
| 84 | | - if (!time_after(jiffies, status->reorder_time + |
|---|
| 85 | | - REORDER_TIMEOUT)) |
|---|
| 78 | + status = (struct mt76_rx_status *)skb->cb; |
|---|
| 79 | + if (!time_after(jiffies, |
|---|
| 80 | + status->reorder_time + |
|---|
| 81 | + mt76_aggr_tid_to_timeo(tid->num))) |
|---|
| 86 | 82 | continue; |
|---|
| 87 | 83 | |
|---|
| 88 | 84 | mt76_rx_aggr_release_frames(tid, frames, status->seqno); |
|---|
| .. | .. |
|---|
| 112 | 108 | |
|---|
| 113 | 109 | if (nframes) |
|---|
| 114 | 110 | ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, |
|---|
| 115 | | - REORDER_TIMEOUT); |
|---|
| 111 | + mt76_aggr_tid_to_timeo(tid->num)); |
|---|
| 116 | 112 | mt76_rx_complete(dev, &frames, NULL); |
|---|
| 117 | 113 | |
|---|
| 118 | 114 | rcu_read_unlock(); |
|---|
| .. | .. |
|---|
| 122 | 118 | static void |
|---|
| 123 | 119 | mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) |
|---|
| 124 | 120 | { |
|---|
| 125 | | - struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; |
|---|
| 126 | | - struct ieee80211_bar *bar = (struct ieee80211_bar *) skb->data; |
|---|
| 121 | + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; |
|---|
| 122 | + struct ieee80211_bar *bar = mt76_skb_get_hdr(skb); |
|---|
| 127 | 123 | struct mt76_wcid *wcid = status->wcid; |
|---|
| 128 | 124 | struct mt76_rx_tid *tid; |
|---|
| 129 | 125 | u16 seqno; |
|---|
| .. | .. |
|---|
| 135 | 131 | return; |
|---|
| 136 | 132 | |
|---|
| 137 | 133 | status->tid = le16_to_cpu(bar->control) >> 12; |
|---|
| 138 | | - seqno = le16_to_cpu(bar->start_seq_num) >> 4; |
|---|
| 134 | + seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num)); |
|---|
| 139 | 135 | tid = rcu_dereference(wcid->aggr[status->tid]); |
|---|
| 140 | 136 | if (!tid) |
|---|
| 141 | 137 | return; |
|---|
| 142 | 138 | |
|---|
| 143 | 139 | spin_lock_bh(&tid->lock); |
|---|
| 144 | | - mt76_rx_aggr_release_frames(tid, frames, seqno); |
|---|
| 145 | | - mt76_rx_aggr_release_head(tid, frames); |
|---|
| 140 | + if (!tid->stopped) { |
|---|
| 141 | + mt76_rx_aggr_release_frames(tid, frames, seqno); |
|---|
| 142 | + mt76_rx_aggr_release_head(tid, frames); |
|---|
| 143 | + } |
|---|
| 146 | 144 | spin_unlock_bh(&tid->lock); |
|---|
| 147 | 145 | } |
|---|
| 148 | 146 | |
|---|
| 149 | 147 | void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) |
|---|
| 150 | 148 | { |
|---|
| 151 | | - struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; |
|---|
| 152 | | - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
|---|
| 149 | + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; |
|---|
| 150 | + struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); |
|---|
| 153 | 151 | struct mt76_wcid *wcid = status->wcid; |
|---|
| 154 | 152 | struct ieee80211_sta *sta; |
|---|
| 155 | 153 | struct mt76_rx_tid *tid; |
|---|
| .. | .. |
|---|
| 233 | 231 | tid->nframes++; |
|---|
| 234 | 232 | mt76_rx_aggr_release_head(tid, frames); |
|---|
| 235 | 233 | |
|---|
| 236 | | - ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, REORDER_TIMEOUT); |
|---|
| 234 | + ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, |
|---|
| 235 | + mt76_aggr_tid_to_timeo(tid->num)); |
|---|
| 237 | 236 | |
|---|
| 238 | 237 | out: |
|---|
| 239 | 238 | spin_unlock_bh(&tid->lock); |
|---|
| .. | .. |
|---|
| 253 | 252 | tid->dev = dev; |
|---|
| 254 | 253 | tid->head = ssn; |
|---|
| 255 | 254 | tid->size = size; |
|---|
| 255 | + tid->num = tidno; |
|---|
| 256 | 256 | INIT_DELAYED_WORK(&tid->reorder_work, mt76_rx_aggr_reorder_work); |
|---|
| 257 | 257 | spin_lock_init(&tid->lock); |
|---|
| 258 | 258 | |
|---|
| .. | .. |
|---|
| 266 | 266 | { |
|---|
| 267 | 267 | u16 size = tid->size; |
|---|
| 268 | 268 | int i; |
|---|
| 269 | | - |
|---|
| 270 | | - cancel_delayed_work(&tid->reorder_work); |
|---|
| 271 | 269 | |
|---|
| 272 | 270 | spin_lock_bh(&tid->lock); |
|---|
| 273 | 271 | |
|---|
| .. | .. |
|---|
| 284 | 282 | } |
|---|
| 285 | 283 | |
|---|
| 286 | 284 | spin_unlock_bh(&tid->lock); |
|---|
| 285 | + |
|---|
| 286 | + cancel_delayed_work_sync(&tid->reorder_work); |
|---|
| 287 | 287 | } |
|---|
| 288 | 288 | |
|---|
| 289 | 289 | void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno) |
|---|
| 290 | 290 | { |
|---|
| 291 | | - struct mt76_rx_tid *tid; |
|---|
| 291 | + struct mt76_rx_tid *tid = NULL; |
|---|
| 292 | 292 | |
|---|
| 293 | | - rcu_read_lock(); |
|---|
| 294 | | - |
|---|
| 295 | | - tid = rcu_dereference(wcid->aggr[tidno]); |
|---|
| 293 | + tid = rcu_replace_pointer(wcid->aggr[tidno], tid, |
|---|
| 294 | + lockdep_is_held(&dev->mutex)); |
|---|
| 296 | 295 | if (tid) { |
|---|
| 297 | | - rcu_assign_pointer(wcid->aggr[tidno], NULL); |
|---|
| 298 | 296 | mt76_rx_aggr_shutdown(dev, tid); |
|---|
| 299 | 297 | kfree_rcu(tid, rcu_head); |
|---|
| 300 | 298 | } |
|---|
| 301 | | - |
|---|
| 302 | | - rcu_read_unlock(); |
|---|
| 303 | 299 | } |
|---|
| 304 | 300 | EXPORT_SYMBOL_GPL(mt76_rx_aggr_stop); |
|---|