linux/drivers/net/wireless/ath/wil6210/rx_reorder.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
   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 */
  16
  17#include "wil6210.h"
  18#include "txrx.h"
  19
  20#define SEQ_MODULO 0x1000
  21#define SEQ_MASK   0xfff
  22
  23static inline int seq_less(u16 sq1, u16 sq2)
  24{
  25        return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
  26}
  27
  28static inline u16 seq_inc(u16 sq)
  29{
  30        return (sq + 1) & SEQ_MASK;
  31}
  32
  33static inline u16 seq_sub(u16 sq1, u16 sq2)
  34{
  35        return (sq1 - sq2) & SEQ_MASK;
  36}
  37
  38static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq)
  39{
  40        return seq_sub(seq, r->ssn) % r->buf_size;
  41}
  42
  43static void wil_release_reorder_frame(struct wil6210_priv *wil,
  44                                      struct wil_tid_ampdu_rx *r,
  45                                      int index)
  46{
  47        struct net_device *ndev = wil_to_ndev(wil);
  48        struct sk_buff *skb = r->reorder_buf[index];
  49
  50        if (!skb)
  51                goto no_frame;
  52
  53        /* release the frame from the reorder ring buffer */
  54        r->stored_mpdu_num--;
  55        r->reorder_buf[index] = NULL;
  56        wil_netif_rx_any(skb, ndev);
  57
  58no_frame:
  59        r->head_seq_num = seq_inc(r->head_seq_num);
  60}
  61
  62static void wil_release_reorder_frames(struct wil6210_priv *wil,
  63                                       struct wil_tid_ampdu_rx *r,
  64                                       u16 hseq)
  65{
  66        int index;
  67
  68        /* note: this function is never called with
  69         * hseq preceding r->head_seq_num, i.e it is always true
  70         * !seq_less(hseq, r->head_seq_num)
  71         * and thus on loop exit it should be
  72         * r->head_seq_num == hseq
  73         */
  74        while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) {
  75                index = reorder_index(r, r->head_seq_num);
  76                wil_release_reorder_frame(wil, r, index);
  77        }
  78        r->head_seq_num = hseq;
  79}
  80
  81static void wil_reorder_release(struct wil6210_priv *wil,
  82                                struct wil_tid_ampdu_rx *r)
  83{
  84        int index = reorder_index(r, r->head_seq_num);
  85
  86        while (r->reorder_buf[index]) {
  87                wil_release_reorder_frame(wil, r, index);
  88                index = reorder_index(r, r->head_seq_num);
  89        }
  90}
  91
  92/* called in NAPI context */
  93void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
  94__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
  95{
  96        struct net_device *ndev = wil_to_ndev(wil);
  97        struct vring_rx_desc *d = wil_skb_rxdesc(skb);
  98        int tid = wil_rxdesc_tid(d);
  99        int cid = wil_rxdesc_cid(d);
 100        int mid = wil_rxdesc_mid(d);
 101        u16 seq = wil_rxdesc_seq(d);
 102        int mcast = wil_rxdesc_mcast(d);
 103        struct wil_sta_info *sta = &wil->sta[cid];
 104        struct wil_tid_ampdu_rx *r;
 105        u16 hseq;
 106        int index;
 107
 108        wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n",
 109                     mid, cid, tid, seq, mcast);
 110
 111        if (unlikely(mcast)) {
 112                wil_netif_rx_any(skb, ndev);
 113                return;
 114        }
 115
 116        spin_lock(&sta->tid_rx_lock);
 117
 118        r = sta->tid_rx[tid];
 119        if (!r) {
 120                wil_netif_rx_any(skb, ndev);
 121                goto out;
 122        }
 123
 124        r->total++;
 125        hseq = r->head_seq_num;
 126
 127        /** Due to the race between WMI events, where BACK establishment
 128         * reported, and data Rx, few packets may be pass up before reorder
 129         * buffer get allocated. Catch up by pretending SSN is what we
 130         * see in the 1-st Rx packet
 131         *
 132         * Another scenario, Rx get delayed and we got packet from before
 133         * BACK. Pass it to the stack and wait.
 134         */
 135        if (r->first_time) {
 136                r->first_time = false;
 137                if (seq != r->head_seq_num) {
 138                        if (seq_less(seq, r->head_seq_num)) {
 139                                wil_err(wil,
 140                                        "Error: frame with early sequence 0x%03x, should be 0x%03x. Waiting...\n",
 141                                        seq, r->head_seq_num);
 142                                r->first_time = true;
 143                                wil_netif_rx_any(skb, ndev);
 144                                goto out;
 145                        }
 146                        wil_err(wil,
 147                                "Error: 1-st frame with wrong sequence 0x%03x, should be 0x%03x. Fixing...\n",
 148                                seq, r->head_seq_num);
 149                        r->head_seq_num = seq;
 150                        r->ssn = seq;
 151                }
 152        }
 153
 154        /* frame with out of date sequence number */
 155        if (seq_less(seq, r->head_seq_num)) {
 156                r->ssn_last_drop = seq;
 157                r->drop_old++;
 158                wil_dbg_txrx(wil, "Rx drop: old seq 0x%03x head 0x%03x\n",
 159                             seq, r->head_seq_num);
 160                dev_kfree_skb(skb);
 161                goto out;
 162        }
 163
 164        /*
 165         * If frame the sequence number exceeds our buffering window
 166         * size release some previous frames to make room for this one.
 167         */
 168        if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
 169                hseq = seq_inc(seq_sub(seq, r->buf_size));
 170                /* release stored frames up to new head to stack */
 171                wil_release_reorder_frames(wil, r, hseq);
 172        }
 173
 174        /* Now the new frame is always in the range of the reordering buffer */
 175
 176        index = reorder_index(r, seq);
 177
 178        /* check if we already stored this frame */
 179        if (r->reorder_buf[index]) {
 180                r->drop_dup++;
 181                wil_dbg_txrx(wil, "Rx drop: dup seq 0x%03x\n", seq);
 182                dev_kfree_skb(skb);
 183                goto out;
 184        }
 185
 186        /*
 187         * If the current MPDU is in the right order and nothing else
 188         * is stored we can process it directly, no need to buffer it.
 189         * If it is first but there's something stored, we may be able
 190         * to release frames after this one.
 191         */
 192        if (seq == r->head_seq_num && r->stored_mpdu_num == 0) {
 193                r->head_seq_num = seq_inc(r->head_seq_num);
 194                wil_netif_rx_any(skb, ndev);
 195                goto out;
 196        }
 197
 198        /* put the frame in the reordering buffer */
 199        r->reorder_buf[index] = skb;
 200        r->reorder_time[index] = jiffies;
 201        r->stored_mpdu_num++;
 202        wil_reorder_release(wil, r);
 203
 204out:
 205        spin_unlock(&sta->tid_rx_lock);
 206}
 207
 208/* process BAR frame, called in NAPI context */
 209void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq)
 210{
 211        struct wil_sta_info *sta = &wil->sta[cid];
 212        struct wil_tid_ampdu_rx *r;
 213
 214        spin_lock(&sta->tid_rx_lock);
 215
 216        r = sta->tid_rx[tid];
 217        if (!r) {
 218                wil_err(wil, "BAR for non-existing CID %d TID %d\n", cid, tid);
 219                goto out;
 220        }
 221        if (seq_less(seq, r->head_seq_num)) {
 222                wil_err(wil, "BAR Seq 0x%03x preceding head 0x%03x\n",
 223                        seq, r->head_seq_num);
 224                goto out;
 225        }
 226        wil_dbg_txrx(wil, "BAR: CID %d TID %d Seq 0x%03x head 0x%03x\n",
 227                     cid, tid, seq, r->head_seq_num);
 228        wil_release_reorder_frames(wil, r, seq);
 229
 230out:
 231        spin_unlock(&sta->tid_rx_lock);
 232}
 233
 234struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
 235                                                int size, u16 ssn)
 236{
 237        struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
 238
 239        if (!r)
 240                return NULL;
 241
 242        r->reorder_buf =
 243                kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL);
 244        r->reorder_time =
 245                kcalloc(size, sizeof(unsigned long), GFP_KERNEL);
 246        if (!r->reorder_buf || !r->reorder_time) {
 247                kfree(r->reorder_buf);
 248                kfree(r->reorder_time);
 249                kfree(r);
 250                return NULL;
 251        }
 252
 253        r->ssn = ssn;
 254        r->head_seq_num = ssn;
 255        r->buf_size = size;
 256        r->stored_mpdu_num = 0;
 257        r->first_time = true;
 258        return r;
 259}
 260
 261void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
 262                           struct wil_tid_ampdu_rx *r)
 263{
 264        int i;
 265
 266        if (!r)
 267                return;
 268
 269        /* Do not pass remaining frames to the network stack - it may be
 270         * not expecting to get any more Rx. Rx from here may lead to
 271         * kernel OOPS since some per-socket accounting info was already
 272         * released.
 273         */
 274        for (i = 0; i < r->buf_size; i++)
 275                kfree_skb(r->reorder_buf[i]);
 276
 277        kfree(r->reorder_buf);
 278        kfree(r->reorder_time);
 279        kfree(r);
 280}
 281
 282/* ADDBA processing */
 283static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize)
 284{
 285        u16 max_agg_size = min_t(u16, WIL_MAX_AGG_WSIZE, WIL_MAX_AMPDU_SIZE /
 286                                 (mtu_max + WIL_MAX_MPDU_OVERHEAD));
 287
 288        if (!req_agg_wsize)
 289                return max_agg_size;
 290
 291        return min(max_agg_size, req_agg_wsize);
 292}
 293
 294/* Block Ack - Rx side (recipient) */
 295int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
 296                         u8 dialog_token, __le16 ba_param_set,
 297                         __le16 ba_timeout, __le16 ba_seq_ctrl)
 298__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
 299{
 300        u16 param_set = le16_to_cpu(ba_param_set);
 301        u16 agg_timeout = le16_to_cpu(ba_timeout);
 302        u16 seq_ctrl = le16_to_cpu(ba_seq_ctrl);
 303        struct wil_sta_info *sta;
 304        u8 cid, tid;
 305        u16 agg_wsize = 0;
 306        /* bit 0: A-MSDU supported
 307         * bit 1: policy (should be 0 for us)
 308         * bits 2..5: TID
 309         * bits 6..15: buffer size
 310         */
 311        u16 req_agg_wsize = WIL_GET_BITS(param_set, 6, 15);
 312        bool agg_amsdu = !!(param_set & BIT(0));
 313        int ba_policy = param_set & BIT(1);
 314        u16 status = WLAN_STATUS_SUCCESS;
 315        u16 ssn = seq_ctrl >> 4;
 316        struct wil_tid_ampdu_rx *r;
 317        int rc = 0;
 318
 319        might_sleep();
 320        parse_cidxtid(cidxtid, &cid, &tid);
 321
 322        /* sanity checks */
 323        if (cid >= WIL6210_MAX_CID) {
 324                wil_err(wil, "BACK: invalid CID %d\n", cid);
 325                rc = -EINVAL;
 326                goto out;
 327        }
 328
 329        sta = &wil->sta[cid];
 330        if (sta->status != wil_sta_connected) {
 331                wil_err(wil, "BACK: CID %d not connected\n", cid);
 332                rc = -EINVAL;
 333                goto out;
 334        }
 335
 336        wil_dbg_wmi(wil,
 337                    "ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d SSN 0x%03x\n",
 338                    cid, sta->addr, tid, req_agg_wsize, agg_timeout,
 339                    agg_amsdu ? "+" : "-", !!ba_policy, dialog_token, ssn);
 340
 341        /* apply policies */
 342        if (ba_policy) {
 343                wil_err(wil, "BACK requested unsupported ba_policy == 1\n");
 344                status = WLAN_STATUS_INVALID_QOS_PARAM;
 345        }
 346        if (status == WLAN_STATUS_SUCCESS)
 347                agg_wsize = wil_agg_size(wil, req_agg_wsize);
 348
 349        rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status,
 350                               agg_amsdu, agg_wsize, agg_timeout);
 351        if (rc || (status != WLAN_STATUS_SUCCESS)) {
 352                wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc,
 353                        status);
 354                goto out;
 355        }
 356
 357        /* apply */
 358        r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
 359        spin_lock_bh(&sta->tid_rx_lock);
 360        wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
 361        sta->tid_rx[tid] = r;
 362        spin_unlock_bh(&sta->tid_rx_lock);
 363
 364out:
 365        return rc;
 366}
 367
 368/* BACK - Tx side (originator) */
 369int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize)
 370{
 371        u8 agg_wsize = wil_agg_size(wil, wsize);
 372        u16 agg_timeout = 0;
 373        struct vring_tx_data *txdata = &wil->vring_tx_data[ringid];
 374        int rc = 0;
 375
 376        if (txdata->addba_in_progress) {
 377                wil_dbg_misc(wil, "ADDBA for vring[%d] already in progress\n",
 378                             ringid);
 379                goto out;
 380        }
 381        if (txdata->agg_wsize) {
 382                wil_dbg_misc(wil,
 383                             "ADDBA for vring[%d] already done for wsize %d\n",
 384                             ringid, txdata->agg_wsize);
 385                goto out;
 386        }
 387        txdata->addba_in_progress = true;
 388        rc = wmi_addba(wil, ringid, agg_wsize, agg_timeout);
 389        if (rc) {
 390                wil_err(wil, "wmi_addba failed, rc (%d)", rc);
 391                txdata->addba_in_progress = false;
 392        }
 393
 394out:
 395        return rc;
 396}
 397