• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2014 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 
seq_less(u16 sq1,u16 sq2)23 static inline int seq_less(u16 sq1, u16 sq2)
24 {
25 	return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
26 }
27 
seq_inc(u16 sq)28 static inline u16 seq_inc(u16 sq)
29 {
30 	return (sq + 1) & SEQ_MASK;
31 }
32 
seq_sub(u16 sq1,u16 sq2)33 static inline u16 seq_sub(u16 sq1, u16 sq2)
34 {
35 	return (sq1 - sq2) & SEQ_MASK;
36 }
37 
reorder_index(struct wil_tid_ampdu_rx * r,u16 seq)38 static 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 
wil_release_reorder_frame(struct wil6210_priv * wil,struct wil_tid_ampdu_rx * r,int index)43 static 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 
58 no_frame:
59 	r->head_seq_num = seq_inc(r->head_seq_num);
60 }
61 
wil_release_reorder_frames(struct wil6210_priv * wil,struct wil_tid_ampdu_rx * r,u16 hseq)62 static 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 
wil_reorder_release(struct wil6210_priv * wil,struct wil_tid_ampdu_rx * r)81 static 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 
wil_rx_reorder(struct wil6210_priv * wil,struct sk_buff * skb)92 void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
93 {
94 	struct net_device *ndev = wil_to_ndev(wil);
95 	struct vring_rx_desc *d = wil_skb_rxdesc(skb);
96 	int tid = wil_rxdesc_tid(d);
97 	int cid = wil_rxdesc_cid(d);
98 	int mid = wil_rxdesc_mid(d);
99 	u16 seq = wil_rxdesc_seq(d);
100 	struct wil_sta_info *sta = &wil->sta[cid];
101 	struct wil_tid_ampdu_rx *r;
102 	u16 hseq;
103 	int index;
104 	unsigned long flags;
105 
106 	wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
107 		     mid, cid, tid, seq);
108 
109 	spin_lock_irqsave(&sta->tid_rx_lock, flags);
110 
111 	r = sta->tid_rx[tid];
112 	if (!r) {
113 		spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
114 		wil_netif_rx_any(skb, ndev);
115 		return;
116 	}
117 
118 	hseq = r->head_seq_num;
119 
120 	/** Due to the race between WMI events, where BACK establishment
121 	 * reported, and data Rx, few packets may be pass up before reorder
122 	 * buffer get allocated. Catch up by pretending SSN is what we
123 	 * see in the 1-st Rx packet
124 	 */
125 	if (r->first_time) {
126 		r->first_time = false;
127 		if (seq != r->head_seq_num) {
128 			wil_err(wil, "Error: 1-st frame with wrong sequence"
129 				" %d, should be %d. Fixing...\n", seq,
130 				r->head_seq_num);
131 			r->head_seq_num = seq;
132 			r->ssn = seq;
133 		}
134 	}
135 
136 	/* frame with out of date sequence number */
137 	if (seq_less(seq, r->head_seq_num)) {
138 		r->ssn_last_drop = seq;
139 		dev_kfree_skb(skb);
140 		goto out;
141 	}
142 
143 	/*
144 	 * If frame the sequence number exceeds our buffering window
145 	 * size release some previous frames to make room for this one.
146 	 */
147 	if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
148 		hseq = seq_inc(seq_sub(seq, r->buf_size));
149 		/* release stored frames up to new head to stack */
150 		wil_release_reorder_frames(wil, r, hseq);
151 	}
152 
153 	/* Now the new frame is always in the range of the reordering buffer */
154 
155 	index = reorder_index(r, seq);
156 
157 	/* check if we already stored this frame */
158 	if (r->reorder_buf[index]) {
159 		dev_kfree_skb(skb);
160 		goto out;
161 	}
162 
163 	/*
164 	 * If the current MPDU is in the right order and nothing else
165 	 * is stored we can process it directly, no need to buffer it.
166 	 * If it is first but there's something stored, we may be able
167 	 * to release frames after this one.
168 	 */
169 	if (seq == r->head_seq_num && r->stored_mpdu_num == 0) {
170 		r->head_seq_num = seq_inc(r->head_seq_num);
171 		wil_netif_rx_any(skb, ndev);
172 		goto out;
173 	}
174 
175 	/* put the frame in the reordering buffer */
176 	r->reorder_buf[index] = skb;
177 	r->reorder_time[index] = jiffies;
178 	r->stored_mpdu_num++;
179 	wil_reorder_release(wil, r);
180 
181 out:
182 	spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
183 }
184 
wil_tid_ampdu_rx_alloc(struct wil6210_priv * wil,int size,u16 ssn)185 struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
186 						int size, u16 ssn)
187 {
188 	struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
189 
190 	if (!r)
191 		return NULL;
192 
193 	r->reorder_buf =
194 		kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL);
195 	r->reorder_time =
196 		kcalloc(size, sizeof(unsigned long), GFP_KERNEL);
197 	if (!r->reorder_buf || !r->reorder_time) {
198 		kfree(r->reorder_buf);
199 		kfree(r->reorder_time);
200 		kfree(r);
201 		return NULL;
202 	}
203 
204 	r->ssn = ssn;
205 	r->head_seq_num = ssn;
206 	r->buf_size = size;
207 	r->stored_mpdu_num = 0;
208 	r->first_time = true;
209 	return r;
210 }
211 
wil_tid_ampdu_rx_free(struct wil6210_priv * wil,struct wil_tid_ampdu_rx * r)212 void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
213 			   struct wil_tid_ampdu_rx *r)
214 {
215 	if (!r)
216 		return;
217 	wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size);
218 	kfree(r->reorder_buf);
219 	kfree(r->reorder_time);
220 	kfree(r);
221 }
222