1 #include "wil6210.h" 2 #include "txrx.h" 3 4 #define SEQ_MODULO 0x1000 5 #define SEQ_MASK 0xfff 6 7 static inline int seq_less(u16 sq1, u16 sq2) 8 { 9 return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1); 10 } 11 12 static inline u16 seq_inc(u16 sq) 13 { 14 return (sq + 1) & SEQ_MASK; 15 } 16 17 static inline u16 seq_sub(u16 sq1, u16 sq2) 18 { 19 return (sq1 - sq2) & SEQ_MASK; 20 } 21 22 static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq) 23 { 24 return seq_sub(seq, r->ssn) % r->buf_size; 25 } 26 27 static void wil_release_reorder_frame(struct wil6210_priv *wil, 28 struct wil_tid_ampdu_rx *r, 29 int index) 30 { 31 struct net_device *ndev = wil_to_ndev(wil); 32 struct sk_buff *skb = r->reorder_buf[index]; 33 34 if (!skb) 35 goto no_frame; 36 37 /* release the frame from the reorder ring buffer */ 38 r->stored_mpdu_num--; 39 r->reorder_buf[index] = NULL; 40 wil_netif_rx_any(skb, ndev); 41 42 no_frame: 43 r->head_seq_num = seq_inc(r->head_seq_num); 44 } 45 46 static void wil_release_reorder_frames(struct wil6210_priv *wil, 47 struct wil_tid_ampdu_rx *r, 48 u16 hseq) 49 { 50 int index; 51 52 /* note: this function is never called with 53 * hseq preceding r->head_seq_num, i.e it is always true 54 * !seq_less(hseq, r->head_seq_num) 55 * and thus on loop exit it should be 56 * r->head_seq_num == hseq 57 */ 58 while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) { 59 index = reorder_index(r, r->head_seq_num); 60 wil_release_reorder_frame(wil, r, index); 61 } 62 r->head_seq_num = hseq; 63 } 64 65 static void wil_reorder_release(struct wil6210_priv *wil, 66 struct wil_tid_ampdu_rx *r) 67 { 68 int index = reorder_index(r, r->head_seq_num); 69 70 while (r->reorder_buf[index]) { 71 wil_release_reorder_frame(wil, r, index); 72 index = reorder_index(r, r->head_seq_num); 73 } 74 } 75 76 void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) 77 { 78 struct net_device *ndev = wil_to_ndev(wil); 79 struct vring_rx_desc *d = wil_skb_rxdesc(skb); 80 int tid = wil_rxdesc_tid(d); 81 int cid = wil_rxdesc_cid(d); 82 int mid = wil_rxdesc_mid(d); 83 u16 seq = wil_rxdesc_seq(d); 84 struct wil_sta_info *sta = &wil->sta[cid]; 85 struct wil_tid_ampdu_rx *r = sta->tid_rx[tid]; 86 u16 hseq; 87 int index; 88 89 wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n", 90 mid, cid, tid, seq); 91 92 if (!r) { 93 wil_netif_rx_any(skb, ndev); 94 return; 95 } 96 97 hseq = r->head_seq_num; 98 99 spin_lock(&r->reorder_lock); 100 101 /** Due to the race between WMI events, where BACK establishment 102 * reported, and data Rx, few packets may be pass up before reorder 103 * buffer get allocated. Catch up by pretending SSN is what we 104 * see in the 1-st Rx packet 105 */ 106 if (r->first_time) { 107 r->first_time = false; 108 if (seq != r->head_seq_num) { 109 wil_err(wil, "Error: 1-st frame with wrong sequence" 110 " %d, should be %d. Fixing...\n", seq, 111 r->head_seq_num); 112 r->head_seq_num = seq; 113 r->ssn = seq; 114 } 115 } 116 117 /* frame with out of date sequence number */ 118 if (seq_less(seq, r->head_seq_num)) { 119 r->ssn_last_drop = seq; 120 dev_kfree_skb(skb); 121 goto out; 122 } 123 124 /* 125 * If frame the sequence number exceeds our buffering window 126 * size release some previous frames to make room for this one. 127 */ 128 if (!seq_less(seq, r->head_seq_num + r->buf_size)) { 129 hseq = seq_inc(seq_sub(seq, r->buf_size)); 130 /* release stored frames up to new head to stack */ 131 wil_release_reorder_frames(wil, r, hseq); 132 } 133 134 /* Now the new frame is always in the range of the reordering buffer */ 135 136 index = reorder_index(r, seq); 137 138 /* check if we already stored this frame */ 139 if (r->reorder_buf[index]) { 140 dev_kfree_skb(skb); 141 goto out; 142 } 143 144 /* 145 * If the current MPDU is in the right order and nothing else 146 * is stored we can process it directly, no need to buffer it. 147 * If it is first but there's something stored, we may be able 148 * to release frames after this one. 149 */ 150 if (seq == r->head_seq_num && r->stored_mpdu_num == 0) { 151 r->head_seq_num = seq_inc(r->head_seq_num); 152 wil_netif_rx_any(skb, ndev); 153 goto out; 154 } 155 156 /* put the frame in the reordering buffer */ 157 r->reorder_buf[index] = skb; 158 r->reorder_time[index] = jiffies; 159 r->stored_mpdu_num++; 160 wil_reorder_release(wil, r); 161 162 out: 163 spin_unlock(&r->reorder_lock); 164 } 165 166 struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, 167 int size, u16 ssn) 168 { 169 struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL); 170 if (!r) 171 return NULL; 172 173 r->reorder_buf = 174 kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL); 175 r->reorder_time = 176 kcalloc(size, sizeof(unsigned long), GFP_KERNEL); 177 if (!r->reorder_buf || !r->reorder_time) { 178 kfree(r->reorder_buf); 179 kfree(r->reorder_time); 180 kfree(r); 181 return NULL; 182 } 183 184 spin_lock_init(&r->reorder_lock); 185 r->ssn = ssn; 186 r->head_seq_num = ssn; 187 r->buf_size = size; 188 r->stored_mpdu_num = 0; 189 r->first_time = true; 190 return r; 191 } 192 193 void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, 194 struct wil_tid_ampdu_rx *r) 195 { 196 if (!r) 197 return; 198 wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size); 199 kfree(r->reorder_buf); 200 kfree(r->reorder_time); 201 kfree(r); 202 } 203