Commit | Line | Data |
---|---|---|
b4490f42 VK |
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 | while (seq_less(r->head_seq_num, hseq)) { | |
53 | index = reorder_index(r, r->head_seq_num); | |
54 | wil_release_reorder_frame(wil, r, index); | |
55 | } | |
56 | } | |
57 | ||
58 | static void wil_reorder_release(struct wil6210_priv *wil, | |
59 | struct wil_tid_ampdu_rx *r) | |
60 | { | |
61 | int index = reorder_index(r, r->head_seq_num); | |
62 | ||
63 | while (r->reorder_buf[index]) { | |
64 | wil_release_reorder_frame(wil, r, index); | |
65 | index = reorder_index(r, r->head_seq_num); | |
66 | } | |
67 | } | |
68 | ||
69 | void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) | |
70 | { | |
71 | struct net_device *ndev = wil_to_ndev(wil); | |
72 | struct vring_rx_desc *d = wil_skb_rxdesc(skb); | |
73 | int tid = wil_rxdesc_tid(d); | |
74 | int cid = wil_rxdesc_cid(d); | |
75 | int mid = wil_rxdesc_mid(d); | |
76 | u16 seq = wil_rxdesc_seq(d); | |
77 | struct wil_sta_info *sta = &wil->sta[cid]; | |
78 | struct wil_tid_ampdu_rx *r = sta->tid_rx[tid]; | |
79 | u16 hseq; | |
80 | int index; | |
81 | ||
82 | wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n", | |
83 | mid, cid, tid, seq); | |
84 | ||
85 | if (!r) { | |
86 | wil_netif_rx_any(skb, ndev); | |
87 | return; | |
88 | } | |
89 | ||
90 | hseq = r->head_seq_num; | |
91 | ||
92 | spin_lock(&r->reorder_lock); | |
93 | ||
c888cdd4 VK |
94 | /** Due to the race between WMI events, where BACK establishment |
95 | * reported, and data Rx, few packets may be pass up before reorder | |
96 | * buffer get allocated. Catch up by pretending SSN is what we | |
97 | * see in the 1-st Rx packet | |
98 | */ | |
99 | if (r->first_time) { | |
100 | r->first_time = false; | |
101 | if (seq != r->head_seq_num) { | |
102 | wil_err(wil, "Error: 1-st frame with wrong sequence" | |
103 | " %d, should be %d. Fixing...\n", seq, | |
104 | r->head_seq_num); | |
105 | r->head_seq_num = seq; | |
106 | r->ssn = seq; | |
107 | } | |
108 | } | |
109 | ||
b4490f42 VK |
110 | /* frame with out of date sequence number */ |
111 | if (seq_less(seq, r->head_seq_num)) { | |
112 | dev_kfree_skb(skb); | |
113 | goto out; | |
114 | } | |
115 | ||
116 | /* | |
117 | * If frame the sequence number exceeds our buffering window | |
118 | * size release some previous frames to make room for this one. | |
119 | */ | |
120 | if (!seq_less(seq, r->head_seq_num + r->buf_size)) { | |
121 | hseq = seq_inc(seq_sub(seq, r->buf_size)); | |
122 | /* release stored frames up to new head to stack */ | |
123 | wil_release_reorder_frames(wil, r, hseq); | |
124 | } | |
125 | ||
126 | /* Now the new frame is always in the range of the reordering buffer */ | |
127 | ||
128 | index = reorder_index(r, seq); | |
129 | ||
130 | /* check if we already stored this frame */ | |
131 | if (r->reorder_buf[index]) { | |
132 | dev_kfree_skb(skb); | |
133 | goto out; | |
134 | } | |
135 | ||
136 | /* | |
137 | * If the current MPDU is in the right order and nothing else | |
138 | * is stored we can process it directly, no need to buffer it. | |
139 | * If it is first but there's something stored, we may be able | |
140 | * to release frames after this one. | |
141 | */ | |
142 | if (seq == r->head_seq_num && r->stored_mpdu_num == 0) { | |
143 | r->head_seq_num = seq_inc(r->head_seq_num); | |
144 | wil_netif_rx_any(skb, ndev); | |
145 | goto out; | |
146 | } | |
147 | ||
148 | /* put the frame in the reordering buffer */ | |
149 | r->reorder_buf[index] = skb; | |
150 | r->reorder_time[index] = jiffies; | |
151 | r->stored_mpdu_num++; | |
152 | wil_reorder_release(wil, r); | |
153 | ||
154 | out: | |
155 | spin_unlock(&r->reorder_lock); | |
156 | } | |
157 | ||
158 | struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, | |
159 | int size, u16 ssn) | |
160 | { | |
161 | struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL); | |
162 | if (!r) | |
163 | return NULL; | |
164 | ||
165 | r->reorder_buf = | |
166 | kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL); | |
167 | r->reorder_time = | |
168 | kcalloc(size, sizeof(unsigned long), GFP_KERNEL); | |
169 | if (!r->reorder_buf || !r->reorder_time) { | |
170 | kfree(r->reorder_buf); | |
171 | kfree(r->reorder_time); | |
172 | kfree(r); | |
173 | return NULL; | |
174 | } | |
175 | ||
176 | spin_lock_init(&r->reorder_lock); | |
177 | r->ssn = ssn; | |
178 | r->head_seq_num = ssn; | |
179 | r->buf_size = size; | |
180 | r->stored_mpdu_num = 0; | |
c888cdd4 | 181 | r->first_time = true; |
b4490f42 VK |
182 | return r; |
183 | } | |
184 | ||
185 | void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, | |
186 | struct wil_tid_ampdu_rx *r) | |
187 | { | |
188 | if (!r) | |
189 | return; | |
190 | wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size); | |
191 | kfree(r->reorder_buf); | |
192 | kfree(r->reorder_time); | |
193 | kfree(r); | |
194 | } |