1*6c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC 2*6c92544dSBjoern A. Zeeb /* 3*6c92544dSBjoern A. Zeeb * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name> 4*6c92544dSBjoern A. Zeeb */ 5*6c92544dSBjoern A. Zeeb #include "mt76.h" 6*6c92544dSBjoern A. Zeeb 7*6c92544dSBjoern A. Zeeb static unsigned long mt76_aggr_tid_to_timeo(u8 tidno) 8*6c92544dSBjoern A. Zeeb { 9*6c92544dSBjoern A. Zeeb /* Currently voice traffic (AC_VO) always runs without aggregation, 10*6c92544dSBjoern A. Zeeb * no special handling is needed. AC_BE/AC_BK use tids 0-3. Just check 11*6c92544dSBjoern A. Zeeb * for non AC_BK/AC_BE and set smaller timeout for it. */ 12*6c92544dSBjoern A. Zeeb return HZ / (tidno >= 4 ? 25 : 10); 13*6c92544dSBjoern A. Zeeb } 14*6c92544dSBjoern A. Zeeb 15*6c92544dSBjoern A. Zeeb static void 16*6c92544dSBjoern A. Zeeb mt76_aggr_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames, int idx) 17*6c92544dSBjoern A. Zeeb { 18*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 19*6c92544dSBjoern A. Zeeb 20*6c92544dSBjoern A. Zeeb tid->head = ieee80211_sn_inc(tid->head); 21*6c92544dSBjoern A. Zeeb 22*6c92544dSBjoern A. Zeeb skb = tid->reorder_buf[idx]; 23*6c92544dSBjoern A. Zeeb if (!skb) 24*6c92544dSBjoern A. Zeeb return; 25*6c92544dSBjoern A. Zeeb 26*6c92544dSBjoern A. Zeeb tid->reorder_buf[idx] = NULL; 27*6c92544dSBjoern A. Zeeb tid->nframes--; 28*6c92544dSBjoern A. Zeeb __skb_queue_tail(frames, skb); 29*6c92544dSBjoern A. Zeeb } 30*6c92544dSBjoern A. Zeeb 31*6c92544dSBjoern A. Zeeb static void 32*6c92544dSBjoern A. Zeeb mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid, 33*6c92544dSBjoern A. Zeeb struct sk_buff_head *frames, 34*6c92544dSBjoern A. Zeeb u16 head) 35*6c92544dSBjoern A. Zeeb { 36*6c92544dSBjoern A. Zeeb int idx; 37*6c92544dSBjoern A. Zeeb 38*6c92544dSBjoern A. Zeeb while (ieee80211_sn_less(tid->head, head)) { 39*6c92544dSBjoern A. Zeeb idx = tid->head % tid->size; 40*6c92544dSBjoern A. Zeeb mt76_aggr_release(tid, frames, idx); 41*6c92544dSBjoern A. Zeeb } 42*6c92544dSBjoern A. Zeeb } 43*6c92544dSBjoern A. Zeeb 44*6c92544dSBjoern A. Zeeb static void 45*6c92544dSBjoern A. Zeeb mt76_rx_aggr_release_head(struct mt76_rx_tid *tid, struct sk_buff_head *frames) 46*6c92544dSBjoern A. Zeeb { 47*6c92544dSBjoern A. Zeeb int idx = tid->head % tid->size; 48*6c92544dSBjoern A. Zeeb 49*6c92544dSBjoern A. Zeeb while (tid->reorder_buf[idx]) { 50*6c92544dSBjoern A. Zeeb mt76_aggr_release(tid, frames, idx); 51*6c92544dSBjoern A. Zeeb idx = tid->head % tid->size; 52*6c92544dSBjoern A. Zeeb } 53*6c92544dSBjoern A. Zeeb } 54*6c92544dSBjoern A. Zeeb 55*6c92544dSBjoern A. Zeeb static void 56*6c92544dSBjoern A. Zeeb mt76_rx_aggr_check_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames) 57*6c92544dSBjoern A. Zeeb { 58*6c92544dSBjoern A. Zeeb struct mt76_rx_status *status; 59*6c92544dSBjoern A. Zeeb struct sk_buff *skb; 60*6c92544dSBjoern A. Zeeb int start, idx, nframes; 61*6c92544dSBjoern A. Zeeb 62*6c92544dSBjoern A. Zeeb if (!tid->nframes) 63*6c92544dSBjoern A. Zeeb return; 64*6c92544dSBjoern A. Zeeb 65*6c92544dSBjoern A. Zeeb mt76_rx_aggr_release_head(tid, frames); 66*6c92544dSBjoern A. Zeeb 67*6c92544dSBjoern A. Zeeb start = tid->head % tid->size; 68*6c92544dSBjoern A. Zeeb nframes = tid->nframes; 69*6c92544dSBjoern A. Zeeb 70*6c92544dSBjoern A. Zeeb for (idx = (tid->head + 1) % tid->size; 71*6c92544dSBjoern A. Zeeb idx != start && nframes; 72*6c92544dSBjoern A. Zeeb idx = (idx + 1) % tid->size) { 73*6c92544dSBjoern A. Zeeb skb = tid->reorder_buf[idx]; 74*6c92544dSBjoern A. Zeeb if (!skb) 75*6c92544dSBjoern A. Zeeb continue; 76*6c92544dSBjoern A. Zeeb 77*6c92544dSBjoern A. Zeeb nframes--; 78*6c92544dSBjoern A. Zeeb status = (struct mt76_rx_status *)skb->cb; 79*6c92544dSBjoern A. Zeeb if (!time_after32(jiffies, 80*6c92544dSBjoern A. Zeeb status->reorder_time + 81*6c92544dSBjoern A. Zeeb mt76_aggr_tid_to_timeo(tid->num))) 82*6c92544dSBjoern A. Zeeb continue; 83*6c92544dSBjoern A. Zeeb 84*6c92544dSBjoern A. Zeeb mt76_rx_aggr_release_frames(tid, frames, status->seqno); 85*6c92544dSBjoern A. Zeeb } 86*6c92544dSBjoern A. Zeeb 87*6c92544dSBjoern A. Zeeb mt76_rx_aggr_release_head(tid, frames); 88*6c92544dSBjoern A. Zeeb } 89*6c92544dSBjoern A. Zeeb 90*6c92544dSBjoern A. Zeeb static void 91*6c92544dSBjoern A. Zeeb mt76_rx_aggr_reorder_work(struct work_struct *work) 92*6c92544dSBjoern A. Zeeb { 93*6c92544dSBjoern A. Zeeb struct mt76_rx_tid *tid = container_of(work, struct mt76_rx_tid, 94*6c92544dSBjoern A. Zeeb reorder_work.work); 95*6c92544dSBjoern A. Zeeb struct mt76_dev *dev = tid->dev; 96*6c92544dSBjoern A. Zeeb struct sk_buff_head frames; 97*6c92544dSBjoern A. Zeeb int nframes; 98*6c92544dSBjoern A. Zeeb 99*6c92544dSBjoern A. Zeeb __skb_queue_head_init(&frames); 100*6c92544dSBjoern A. Zeeb 101*6c92544dSBjoern A. Zeeb local_bh_disable(); 102*6c92544dSBjoern A. Zeeb rcu_read_lock(); 103*6c92544dSBjoern A. Zeeb 104*6c92544dSBjoern A. Zeeb spin_lock(&tid->lock); 105*6c92544dSBjoern A. Zeeb mt76_rx_aggr_check_release(tid, &frames); 106*6c92544dSBjoern A. Zeeb nframes = tid->nframes; 107*6c92544dSBjoern A. Zeeb spin_unlock(&tid->lock); 108*6c92544dSBjoern A. Zeeb 109*6c92544dSBjoern A. Zeeb if (nframes) 110*6c92544dSBjoern A. Zeeb ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, 111*6c92544dSBjoern A. Zeeb mt76_aggr_tid_to_timeo(tid->num)); 112*6c92544dSBjoern A. Zeeb mt76_rx_complete(dev, &frames, NULL); 113*6c92544dSBjoern A. Zeeb 114*6c92544dSBjoern A. Zeeb rcu_read_unlock(); 115*6c92544dSBjoern A. Zeeb local_bh_enable(); 116*6c92544dSBjoern A. Zeeb } 117*6c92544dSBjoern A. Zeeb 118*6c92544dSBjoern A. Zeeb static void 119*6c92544dSBjoern A. Zeeb mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) 120*6c92544dSBjoern A. Zeeb { 121*6c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 122*6c92544dSBjoern A. Zeeb struct ieee80211_bar *bar = mt76_skb_get_hdr(skb); 123*6c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = status->wcid; 124*6c92544dSBjoern A. Zeeb struct mt76_rx_tid *tid; 125*6c92544dSBjoern A. Zeeb u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 126*6c92544dSBjoern A. Zeeb u16 seqno; 127*6c92544dSBjoern A. Zeeb 128*6c92544dSBjoern A. Zeeb if (!ieee80211_is_ctl(bar->frame_control)) 129*6c92544dSBjoern A. Zeeb return; 130*6c92544dSBjoern A. Zeeb 131*6c92544dSBjoern A. Zeeb if (!ieee80211_is_back_req(bar->frame_control)) 132*6c92544dSBjoern A. Zeeb return; 133*6c92544dSBjoern A. Zeeb 134*6c92544dSBjoern A. Zeeb status->qos_ctl = tidno = le16_to_cpu(bar->control) >> 12; 135*6c92544dSBjoern A. Zeeb seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num)); 136*6c92544dSBjoern A. Zeeb tid = rcu_dereference(wcid->aggr[tidno]); 137*6c92544dSBjoern A. Zeeb if (!tid) 138*6c92544dSBjoern A. Zeeb return; 139*6c92544dSBjoern A. Zeeb 140*6c92544dSBjoern A. Zeeb spin_lock_bh(&tid->lock); 141*6c92544dSBjoern A. Zeeb if (!tid->stopped) { 142*6c92544dSBjoern A. Zeeb mt76_rx_aggr_release_frames(tid, frames, seqno); 143*6c92544dSBjoern A. Zeeb mt76_rx_aggr_release_head(tid, frames); 144*6c92544dSBjoern A. Zeeb } 145*6c92544dSBjoern A. Zeeb spin_unlock_bh(&tid->lock); 146*6c92544dSBjoern A. Zeeb } 147*6c92544dSBjoern A. Zeeb 148*6c92544dSBjoern A. Zeeb void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) 149*6c92544dSBjoern A. Zeeb { 150*6c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 151*6c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = status->wcid; 152*6c92544dSBjoern A. Zeeb struct ieee80211_sta *sta; 153*6c92544dSBjoern A. Zeeb struct mt76_rx_tid *tid; 154*6c92544dSBjoern A. Zeeb bool sn_less; 155*6c92544dSBjoern A. Zeeb u16 seqno, head, size, idx; 156*6c92544dSBjoern A. Zeeb u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 157*6c92544dSBjoern A. Zeeb u8 ackp; 158*6c92544dSBjoern A. Zeeb 159*6c92544dSBjoern A. Zeeb __skb_queue_tail(frames, skb); 160*6c92544dSBjoern A. Zeeb 161*6c92544dSBjoern A. Zeeb sta = wcid_to_sta(wcid); 162*6c92544dSBjoern A. Zeeb if (!sta) 163*6c92544dSBjoern A. Zeeb return; 164*6c92544dSBjoern A. Zeeb 165*6c92544dSBjoern A. Zeeb if (!status->aggr) { 166*6c92544dSBjoern A. Zeeb if (!(status->flag & RX_FLAG_8023)) 167*6c92544dSBjoern A. Zeeb mt76_rx_aggr_check_ctl(skb, frames); 168*6c92544dSBjoern A. Zeeb return; 169*6c92544dSBjoern A. Zeeb } 170*6c92544dSBjoern A. Zeeb 171*6c92544dSBjoern A. Zeeb /* not part of a BA session */ 172*6c92544dSBjoern A. Zeeb ackp = status->qos_ctl & IEEE80211_QOS_CTL_ACK_POLICY_MASK; 173*6c92544dSBjoern A. Zeeb if (ackp == IEEE80211_QOS_CTL_ACK_POLICY_NOACK) 174*6c92544dSBjoern A. Zeeb return; 175*6c92544dSBjoern A. Zeeb 176*6c92544dSBjoern A. Zeeb tid = rcu_dereference(wcid->aggr[tidno]); 177*6c92544dSBjoern A. Zeeb if (!tid) 178*6c92544dSBjoern A. Zeeb return; 179*6c92544dSBjoern A. Zeeb 180*6c92544dSBjoern A. Zeeb status->flag |= RX_FLAG_DUP_VALIDATED; 181*6c92544dSBjoern A. Zeeb spin_lock_bh(&tid->lock); 182*6c92544dSBjoern A. Zeeb 183*6c92544dSBjoern A. Zeeb if (tid->stopped) 184*6c92544dSBjoern A. Zeeb goto out; 185*6c92544dSBjoern A. Zeeb 186*6c92544dSBjoern A. Zeeb head = tid->head; 187*6c92544dSBjoern A. Zeeb seqno = status->seqno; 188*6c92544dSBjoern A. Zeeb size = tid->size; 189*6c92544dSBjoern A. Zeeb sn_less = ieee80211_sn_less(seqno, head); 190*6c92544dSBjoern A. Zeeb 191*6c92544dSBjoern A. Zeeb if (!tid->started) { 192*6c92544dSBjoern A. Zeeb if (sn_less) 193*6c92544dSBjoern A. Zeeb goto out; 194*6c92544dSBjoern A. Zeeb 195*6c92544dSBjoern A. Zeeb tid->started = true; 196*6c92544dSBjoern A. Zeeb } 197*6c92544dSBjoern A. Zeeb 198*6c92544dSBjoern A. Zeeb if (sn_less) { 199*6c92544dSBjoern A. Zeeb __skb_unlink(skb, frames); 200*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 201*6c92544dSBjoern A. Zeeb goto out; 202*6c92544dSBjoern A. Zeeb } 203*6c92544dSBjoern A. Zeeb 204*6c92544dSBjoern A. Zeeb if (seqno == head) { 205*6c92544dSBjoern A. Zeeb tid->head = ieee80211_sn_inc(head); 206*6c92544dSBjoern A. Zeeb if (tid->nframes) 207*6c92544dSBjoern A. Zeeb mt76_rx_aggr_release_head(tid, frames); 208*6c92544dSBjoern A. Zeeb goto out; 209*6c92544dSBjoern A. Zeeb } 210*6c92544dSBjoern A. Zeeb 211*6c92544dSBjoern A. Zeeb __skb_unlink(skb, frames); 212*6c92544dSBjoern A. Zeeb 213*6c92544dSBjoern A. Zeeb /* 214*6c92544dSBjoern A. Zeeb * Frame sequence number exceeds buffering window, free up some space 215*6c92544dSBjoern A. Zeeb * by releasing previous frames 216*6c92544dSBjoern A. Zeeb */ 217*6c92544dSBjoern A. Zeeb if (!ieee80211_sn_less(seqno, head + size)) { 218*6c92544dSBjoern A. Zeeb head = ieee80211_sn_inc(ieee80211_sn_sub(seqno, size)); 219*6c92544dSBjoern A. Zeeb mt76_rx_aggr_release_frames(tid, frames, head); 220*6c92544dSBjoern A. Zeeb } 221*6c92544dSBjoern A. Zeeb 222*6c92544dSBjoern A. Zeeb idx = seqno % size; 223*6c92544dSBjoern A. Zeeb 224*6c92544dSBjoern A. Zeeb /* Discard if the current slot is already in use */ 225*6c92544dSBjoern A. Zeeb if (tid->reorder_buf[idx]) { 226*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 227*6c92544dSBjoern A. Zeeb goto out; 228*6c92544dSBjoern A. Zeeb } 229*6c92544dSBjoern A. Zeeb 230*6c92544dSBjoern A. Zeeb status->reorder_time = jiffies; 231*6c92544dSBjoern A. Zeeb tid->reorder_buf[idx] = skb; 232*6c92544dSBjoern A. Zeeb tid->nframes++; 233*6c92544dSBjoern A. Zeeb mt76_rx_aggr_release_head(tid, frames); 234*6c92544dSBjoern A. Zeeb 235*6c92544dSBjoern A. Zeeb ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, 236*6c92544dSBjoern A. Zeeb mt76_aggr_tid_to_timeo(tid->num)); 237*6c92544dSBjoern A. Zeeb 238*6c92544dSBjoern A. Zeeb out: 239*6c92544dSBjoern A. Zeeb spin_unlock_bh(&tid->lock); 240*6c92544dSBjoern A. Zeeb } 241*6c92544dSBjoern A. Zeeb 242*6c92544dSBjoern A. Zeeb int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno, 243*6c92544dSBjoern A. Zeeb u16 ssn, u16 size) 244*6c92544dSBjoern A. Zeeb { 245*6c92544dSBjoern A. Zeeb struct mt76_rx_tid *tid; 246*6c92544dSBjoern A. Zeeb 247*6c92544dSBjoern A. Zeeb mt76_rx_aggr_stop(dev, wcid, tidno); 248*6c92544dSBjoern A. Zeeb 249*6c92544dSBjoern A. Zeeb tid = kzalloc(struct_size(tid, reorder_buf, size), GFP_KERNEL); 250*6c92544dSBjoern A. Zeeb if (!tid) 251*6c92544dSBjoern A. Zeeb return -ENOMEM; 252*6c92544dSBjoern A. Zeeb 253*6c92544dSBjoern A. Zeeb tid->dev = dev; 254*6c92544dSBjoern A. Zeeb tid->head = ssn; 255*6c92544dSBjoern A. Zeeb tid->size = size; 256*6c92544dSBjoern A. Zeeb tid->num = tidno; 257*6c92544dSBjoern A. Zeeb INIT_DELAYED_WORK(&tid->reorder_work, mt76_rx_aggr_reorder_work); 258*6c92544dSBjoern A. Zeeb spin_lock_init(&tid->lock); 259*6c92544dSBjoern A. Zeeb 260*6c92544dSBjoern A. Zeeb rcu_assign_pointer(wcid->aggr[tidno], tid); 261*6c92544dSBjoern A. Zeeb 262*6c92544dSBjoern A. Zeeb return 0; 263*6c92544dSBjoern A. Zeeb } 264*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx_aggr_start); 265*6c92544dSBjoern A. Zeeb 266*6c92544dSBjoern A. Zeeb static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) 267*6c92544dSBjoern A. Zeeb { 268*6c92544dSBjoern A. Zeeb u16 size = tid->size; 269*6c92544dSBjoern A. Zeeb int i; 270*6c92544dSBjoern A. Zeeb 271*6c92544dSBjoern A. Zeeb spin_lock_bh(&tid->lock); 272*6c92544dSBjoern A. Zeeb 273*6c92544dSBjoern A. Zeeb tid->stopped = true; 274*6c92544dSBjoern A. Zeeb for (i = 0; tid->nframes && i < size; i++) { 275*6c92544dSBjoern A. Zeeb struct sk_buff *skb = tid->reorder_buf[i]; 276*6c92544dSBjoern A. Zeeb 277*6c92544dSBjoern A. Zeeb if (!skb) 278*6c92544dSBjoern A. Zeeb continue; 279*6c92544dSBjoern A. Zeeb 280*6c92544dSBjoern A. Zeeb tid->reorder_buf[i] = NULL; 281*6c92544dSBjoern A. Zeeb tid->nframes--; 282*6c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 283*6c92544dSBjoern A. Zeeb } 284*6c92544dSBjoern A. Zeeb 285*6c92544dSBjoern A. Zeeb spin_unlock_bh(&tid->lock); 286*6c92544dSBjoern A. Zeeb 287*6c92544dSBjoern A. Zeeb cancel_delayed_work_sync(&tid->reorder_work); 288*6c92544dSBjoern A. Zeeb } 289*6c92544dSBjoern A. Zeeb 290*6c92544dSBjoern A. Zeeb void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno) 291*6c92544dSBjoern A. Zeeb { 292*6c92544dSBjoern A. Zeeb struct mt76_rx_tid *tid = NULL; 293*6c92544dSBjoern A. Zeeb 294*6c92544dSBjoern A. Zeeb tid = rcu_replace_pointer(wcid->aggr[tidno], tid, 295*6c92544dSBjoern A. Zeeb lockdep_is_held(&dev->mutex)); 296*6c92544dSBjoern A. Zeeb if (tid) { 297*6c92544dSBjoern A. Zeeb mt76_rx_aggr_shutdown(dev, tid); 298*6c92544dSBjoern A. Zeeb kfree_rcu(tid, rcu_head); 299*6c92544dSBjoern A. Zeeb } 300*6c92544dSBjoern A. Zeeb } 301*6c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx_aggr_stop); 302