rpcd: iwinfo plugin fixes
[openwrt.git] / package / kernel / mac80211 / patches / 349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch
1 From: Arend van Spriel <arend@broadcom.com>
2 Date: Mon, 11 Apr 2016 11:35:26 +0200
3 Subject: [PATCH] brcmfmac: cleanup ampdu-rx host reorder code
4
5 The code for ampdu-rx host reorder is related to the firmware signalling
6 supported in BCDC protocol. This change moves the code to fwsignal module.
7
8 Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
9 Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
10 Reviewed-by: Franky Lin <franky.lin@broadcom.com>
11 Signed-off-by: Arend van Spriel <arend@broadcom.com>
12 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
13 ---
14
15 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
16 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
17 @@ -351,6 +351,12 @@ brcmf_proto_bcdc_add_tdls_peer(struct br
18  {
19  }
20  
21 +static void brcmf_proto_bcdc_rxreorder(struct brcmf_if *ifp,
22 +                                      struct sk_buff *skb)
23 +{
24 +       brcmf_fws_rxreorder(ifp, skb);
25 +}
26 +
27  int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
28  {
29         struct brcmf_bcdc *bcdc;
30 @@ -372,6 +378,7 @@ int brcmf_proto_bcdc_attach(struct brcmf
31         drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode;
32         drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer;
33         drvr->proto->add_tdls_peer = brcmf_proto_bcdc_add_tdls_peer;
34 +       drvr->proto->rxreorder = brcmf_proto_bcdc_rxreorder;
35         drvr->proto->pd = bcdc;
36  
37         drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
38 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
39 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
40 @@ -40,19 +40,6 @@
41  
42  #define MAX_WAIT_FOR_8021X_TX                  msecs_to_jiffies(950)
43  
44 -/* AMPDU rx reordering definitions */
45 -#define BRCMF_RXREORDER_FLOWID_OFFSET          0
46 -#define BRCMF_RXREORDER_MAXIDX_OFFSET          2
47 -#define BRCMF_RXREORDER_FLAGS_OFFSET           4
48 -#define BRCMF_RXREORDER_CURIDX_OFFSET          6
49 -#define BRCMF_RXREORDER_EXPIDX_OFFSET          8
50 -
51 -#define BRCMF_RXREORDER_DEL_FLOW               0x01
52 -#define BRCMF_RXREORDER_FLUSH_ALL              0x02
53 -#define BRCMF_RXREORDER_CURIDX_VALID           0x04
54 -#define BRCMF_RXREORDER_EXPIDX_VALID           0x08
55 -#define BRCMF_RXREORDER_NEW_HOLE               0x10
56 -
57  #define BRCMF_BSSIDX_INVALID                   -1
58  
59  char *brcmf_ifname(struct brcmf_if *ifp)
60 @@ -342,207 +329,11 @@ void brcmf_netif_rx(struct brcmf_if *ifp
61                 netif_rx_ni(skb);
62  }
63  
64 -static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
65 -                                        u8 start, u8 end,
66 -                                        struct sk_buff_head *skb_list)
67 -{
68 -       /* initialize return list */
69 -       __skb_queue_head_init(skb_list);
70 -
71 -       if (rfi->pend_pkts == 0) {
72 -               brcmf_dbg(INFO, "no packets in reorder queue\n");
73 -               return;
74 -       }
75 -
76 -       do {
77 -               if (rfi->pktslots[start]) {
78 -                       __skb_queue_tail(skb_list, rfi->pktslots[start]);
79 -                       rfi->pktslots[start] = NULL;
80 -               }
81 -               start++;
82 -               if (start > rfi->max_idx)
83 -                       start = 0;
84 -       } while (start != end);
85 -       rfi->pend_pkts -= skb_queue_len(skb_list);
86 -}
87 -
88 -static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data,
89 -                                        struct sk_buff *pkt)
90 -{
91 -       u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
92 -       struct brcmf_ampdu_rx_reorder *rfi;
93 -       struct sk_buff_head reorder_list;
94 -       struct sk_buff *pnext;
95 -       u8 flags;
96 -       u32 buf_size;
97 -
98 -       flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
99 -       flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
100 -
101 -       /* validate flags and flow id */
102 -       if (flags == 0xFF) {
103 -               brcmf_err("invalid flags...so ignore this packet\n");
104 -               brcmf_netif_rx(ifp, pkt, false);
105 -               return;
106 -       }
107 -
108 -       rfi = ifp->drvr->reorder_flows[flow_id];
109 -       if (flags & BRCMF_RXREORDER_DEL_FLOW) {
110 -               brcmf_dbg(INFO, "flow-%d: delete\n",
111 -                         flow_id);
112 -
113 -               if (rfi == NULL) {
114 -                       brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
115 -                                 flow_id);
116 -                       brcmf_netif_rx(ifp, pkt, false);
117 -                       return;
118 -               }
119 -
120 -               brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
121 -                                            &reorder_list);
122 -               /* add the last packet */
123 -               __skb_queue_tail(&reorder_list, pkt);
124 -               kfree(rfi);
125 -               ifp->drvr->reorder_flows[flow_id] = NULL;
126 -               goto netif_rx;
127 -       }
128 -       /* from here on we need a flow reorder instance */
129 -       if (rfi == NULL) {
130 -               buf_size = sizeof(*rfi);
131 -               max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
132 -
133 -               buf_size += (max_idx + 1) * sizeof(pkt);
134 -
135 -               /* allocate space for flow reorder info */
136 -               brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
137 -                         flow_id, max_idx);
138 -               rfi = kzalloc(buf_size, GFP_ATOMIC);
139 -               if (rfi == NULL) {
140 -                       brcmf_err("failed to alloc buffer\n");
141 -                       brcmf_netif_rx(ifp, pkt, false);
142 -                       return;
143 -               }
144 -
145 -               ifp->drvr->reorder_flows[flow_id] = rfi;
146 -               rfi->pktslots = (struct sk_buff **)(rfi+1);
147 -               rfi->max_idx = max_idx;
148 -       }
149 -       if (flags & BRCMF_RXREORDER_NEW_HOLE)  {
150 -               if (rfi->pend_pkts) {
151 -                       brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
152 -                                                    rfi->exp_idx,
153 -                                                    &reorder_list);
154 -                       WARN_ON(rfi->pend_pkts);
155 -               } else {
156 -                       __skb_queue_head_init(&reorder_list);
157 -               }
158 -               rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
159 -               rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
160 -               rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
161 -               rfi->pktslots[rfi->cur_idx] = pkt;
162 -               rfi->pend_pkts++;
163 -               brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
164 -                         flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
165 -       } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
166 -               cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
167 -               exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
168 -
169 -               if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
170 -                       /* still in the current hole */
171 -                       /* enqueue the current on the buffer chain */
172 -                       if (rfi->pktslots[cur_idx] != NULL) {
173 -                               brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
174 -                               brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
175 -                               rfi->pktslots[cur_idx] = NULL;
176 -                       }
177 -                       rfi->pktslots[cur_idx] = pkt;
178 -                       rfi->pend_pkts++;
179 -                       rfi->cur_idx = cur_idx;
180 -                       brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
181 -                                 flow_id, cur_idx, exp_idx, rfi->pend_pkts);
182 -
183 -                       /* can return now as there is no reorder
184 -                        * list to process.
185 -                        */
186 -                       return;
187 -               }
188 -               if (rfi->exp_idx == cur_idx) {
189 -                       if (rfi->pktslots[cur_idx] != NULL) {
190 -                               brcmf_dbg(INFO, "error buffer pending..free it\n");
191 -                               brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
192 -                               rfi->pktslots[cur_idx] = NULL;
193 -                       }
194 -                       rfi->pktslots[cur_idx] = pkt;
195 -                       rfi->pend_pkts++;
196 -
197 -                       /* got the expected one. flush from current to expected
198 -                        * and update expected
199 -                        */
200 -                       brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
201 -                                 flow_id, cur_idx, exp_idx, rfi->pend_pkts);
202 -
203 -                       rfi->cur_idx = cur_idx;
204 -                       rfi->exp_idx = exp_idx;
205 -
206 -                       brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
207 -                                                    &reorder_list);
208 -                       brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
209 -                                 flow_id, skb_queue_len(&reorder_list),
210 -                                 rfi->pend_pkts);
211 -               } else {
212 -                       u8 end_idx;
213 -
214 -                       brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
215 -                                 flow_id, flags, rfi->cur_idx, rfi->exp_idx,
216 -                                 cur_idx, exp_idx);
217 -                       if (flags & BRCMF_RXREORDER_FLUSH_ALL)
218 -                               end_idx = rfi->exp_idx;
219 -                       else
220 -                               end_idx = exp_idx;
221 -
222 -                       /* flush pkts first */
223 -                       brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
224 -                                                    &reorder_list);
225 -
226 -                       if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
227 -                               __skb_queue_tail(&reorder_list, pkt);
228 -                       } else {
229 -                               rfi->pktslots[cur_idx] = pkt;
230 -                               rfi->pend_pkts++;
231 -                       }
232 -                       rfi->exp_idx = exp_idx;
233 -                       rfi->cur_idx = cur_idx;
234 -               }
235 -       } else {
236 -               /* explicity window move updating the expected index */
237 -               exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
238 -
239 -               brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
240 -                         flow_id, flags, rfi->exp_idx, exp_idx);
241 -               if (flags & BRCMF_RXREORDER_FLUSH_ALL)
242 -                       end_idx =  rfi->exp_idx;
243 -               else
244 -                       end_idx =  exp_idx;
245 -
246 -               brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
247 -                                            &reorder_list);
248 -               __skb_queue_tail(&reorder_list, pkt);
249 -               /* set the new expected idx */
250 -               rfi->exp_idx = exp_idx;
251 -       }
252 -netif_rx:
253 -       skb_queue_walk_safe(&reorder_list, pkt, pnext) {
254 -               __skb_unlink(pkt, &reorder_list);
255 -               brcmf_netif_rx(ifp, pkt, false);
256 -       }
257 -}
258 -
259  void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt)
260  {
261         struct brcmf_if *ifp;
262         struct brcmf_bus *bus_if = dev_get_drvdata(dev);
263         struct brcmf_pub *drvr = bus_if->drvr;
264 -       struct brcmf_skb_reorder_data *rd;
265         int ret;
266  
267         brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
268 @@ -557,9 +348,8 @@ void brcmf_rx_frame(struct device *dev,
269                 return;
270         }
271  
272 -       rd = (struct brcmf_skb_reorder_data *)skb->cb;
273 -       if (rd->reorder)
274 -               brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
275 +       if (brcmf_proto_is_reorder_skb(skb))
276 +               brcmf_proto_rxreorder(ifp, skb);
277         else
278                 brcmf_netif_rx(ifp, skb, handle_evnt);
279  }
280 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
281 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
282 @@ -208,10 +208,6 @@ struct brcmf_if {
283         u8 ipv6addr_idx;
284  };
285  
286 -struct brcmf_skb_reorder_data {
287 -       u8 *reorder;
288 -};
289 -
290  int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp);
291  
292  /* Return pointer to interface name */
293 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
294 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
295 @@ -92,6 +92,19 @@ enum brcmf_fws_tlv_len {
296  };
297  #undef BRCMF_FWS_TLV_DEF
298  
299 +/* AMPDU rx reordering definitions */
300 +#define BRCMF_RXREORDER_FLOWID_OFFSET          0
301 +#define BRCMF_RXREORDER_MAXIDX_OFFSET          2
302 +#define BRCMF_RXREORDER_FLAGS_OFFSET           4
303 +#define BRCMF_RXREORDER_CURIDX_OFFSET          6
304 +#define BRCMF_RXREORDER_EXPIDX_OFFSET          8
305 +
306 +#define BRCMF_RXREORDER_DEL_FLOW               0x01
307 +#define BRCMF_RXREORDER_FLUSH_ALL              0x02
308 +#define BRCMF_RXREORDER_CURIDX_VALID           0x04
309 +#define BRCMF_RXREORDER_EXPIDX_VALID           0x08
310 +#define BRCMF_RXREORDER_NEW_HOLE               0x10
311 +
312  #ifdef DEBUG
313  /*
314   * brcmf_fws_tlv_names - array of tlv names.
315 @@ -1614,6 +1627,202 @@ static int brcmf_fws_notify_bcmc_credit_
316         return 0;
317  }
318  
319 +static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
320 +                                        u8 start, u8 end,
321 +                                        struct sk_buff_head *skb_list)
322 +{
323 +       /* initialize return list */
324 +       __skb_queue_head_init(skb_list);
325 +
326 +       if (rfi->pend_pkts == 0) {
327 +               brcmf_dbg(INFO, "no packets in reorder queue\n");
328 +               return;
329 +       }
330 +
331 +       do {
332 +               if (rfi->pktslots[start]) {
333 +                       __skb_queue_tail(skb_list, rfi->pktslots[start]);
334 +                       rfi->pktslots[start] = NULL;
335 +               }
336 +               start++;
337 +               if (start > rfi->max_idx)
338 +                       start = 0;
339 +       } while (start != end);
340 +       rfi->pend_pkts -= skb_queue_len(skb_list);
341 +}
342 +
343 +void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt)
344 +{
345 +       u8 *reorder_data;
346 +       u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
347 +       struct brcmf_ampdu_rx_reorder *rfi;
348 +       struct sk_buff_head reorder_list;
349 +       struct sk_buff *pnext;
350 +       u8 flags;
351 +       u32 buf_size;
352 +
353 +       reorder_data = ((struct brcmf_skb_reorder_data *)pkt->cb)->reorder;
354 +       flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
355 +       flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
356 +
357 +       /* validate flags and flow id */
358 +       if (flags == 0xFF) {
359 +               brcmf_err("invalid flags...so ignore this packet\n");
360 +               brcmf_netif_rx(ifp, pkt, false);
361 +               return;
362 +       }
363 +
364 +       rfi = ifp->drvr->reorder_flows[flow_id];
365 +       if (flags & BRCMF_RXREORDER_DEL_FLOW) {
366 +               brcmf_dbg(INFO, "flow-%d: delete\n",
367 +                         flow_id);
368 +
369 +               if (rfi == NULL) {
370 +                       brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
371 +                                 flow_id);
372 +                       brcmf_netif_rx(ifp, pkt, false);
373 +                       return;
374 +               }
375 +
376 +               brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
377 +                                            &reorder_list);
378 +               /* add the last packet */
379 +               __skb_queue_tail(&reorder_list, pkt);
380 +               kfree(rfi);
381 +               ifp->drvr->reorder_flows[flow_id] = NULL;
382 +               goto netif_rx;
383 +       }
384 +       /* from here on we need a flow reorder instance */
385 +       if (rfi == NULL) {
386 +               buf_size = sizeof(*rfi);
387 +               max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
388 +
389 +               buf_size += (max_idx + 1) * sizeof(pkt);
390 +
391 +               /* allocate space for flow reorder info */
392 +               brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
393 +                         flow_id, max_idx);
394 +               rfi = kzalloc(buf_size, GFP_ATOMIC);
395 +               if (rfi == NULL) {
396 +                       brcmf_err("failed to alloc buffer\n");
397 +                       brcmf_netif_rx(ifp, pkt, false);
398 +                       return;
399 +               }
400 +
401 +               ifp->drvr->reorder_flows[flow_id] = rfi;
402 +               rfi->pktslots = (struct sk_buff **)(rfi + 1);
403 +               rfi->max_idx = max_idx;
404 +       }
405 +       if (flags & BRCMF_RXREORDER_NEW_HOLE)  {
406 +               if (rfi->pend_pkts) {
407 +                       brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
408 +                                                    rfi->exp_idx,
409 +                                                    &reorder_list);
410 +                       WARN_ON(rfi->pend_pkts);
411 +               } else {
412 +                       __skb_queue_head_init(&reorder_list);
413 +               }
414 +               rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
415 +               rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
416 +               rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
417 +               rfi->pktslots[rfi->cur_idx] = pkt;
418 +               rfi->pend_pkts++;
419 +               brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
420 +                         flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
421 +       } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
422 +               cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
423 +               exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
424 +
425 +               if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
426 +                       /* still in the current hole */
427 +                       /* enqueue the current on the buffer chain */
428 +                       if (rfi->pktslots[cur_idx] != NULL) {
429 +                               brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
430 +                               brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
431 +                               rfi->pktslots[cur_idx] = NULL;
432 +                       }
433 +                       rfi->pktslots[cur_idx] = pkt;
434 +                       rfi->pend_pkts++;
435 +                       rfi->cur_idx = cur_idx;
436 +                       brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
437 +                                 flow_id, cur_idx, exp_idx, rfi->pend_pkts);
438 +
439 +                       /* can return now as there is no reorder
440 +                        * list to process.
441 +                        */
442 +                       return;
443 +               }
444 +               if (rfi->exp_idx == cur_idx) {
445 +                       if (rfi->pktslots[cur_idx] != NULL) {
446 +                               brcmf_dbg(INFO, "error buffer pending..free it\n");
447 +                               brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
448 +                               rfi->pktslots[cur_idx] = NULL;
449 +                       }
450 +                       rfi->pktslots[cur_idx] = pkt;
451 +                       rfi->pend_pkts++;
452 +
453 +                       /* got the expected one. flush from current to expected
454 +                        * and update expected
455 +                        */
456 +                       brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
457 +                                 flow_id, cur_idx, exp_idx, rfi->pend_pkts);
458 +
459 +                       rfi->cur_idx = cur_idx;
460 +                       rfi->exp_idx = exp_idx;
461 +
462 +                       brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
463 +                                                    &reorder_list);
464 +                       brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
465 +                                 flow_id, skb_queue_len(&reorder_list),
466 +                                 rfi->pend_pkts);
467 +               } else {
468 +                       u8 end_idx;
469 +
470 +                       brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
471 +                                 flow_id, flags, rfi->cur_idx, rfi->exp_idx,
472 +                                 cur_idx, exp_idx);
473 +                       if (flags & BRCMF_RXREORDER_FLUSH_ALL)
474 +                               end_idx = rfi->exp_idx;
475 +                       else
476 +                               end_idx = exp_idx;
477 +
478 +                       /* flush pkts first */
479 +                       brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
480 +                                                    &reorder_list);
481 +
482 +                       if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
483 +                               __skb_queue_tail(&reorder_list, pkt);
484 +                       } else {
485 +                               rfi->pktslots[cur_idx] = pkt;
486 +                               rfi->pend_pkts++;
487 +                       }
488 +                       rfi->exp_idx = exp_idx;
489 +                       rfi->cur_idx = cur_idx;
490 +               }
491 +       } else {
492 +               /* explicity window move updating the expected index */
493 +               exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
494 +
495 +               brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
496 +                         flow_id, flags, rfi->exp_idx, exp_idx);
497 +               if (flags & BRCMF_RXREORDER_FLUSH_ALL)
498 +                       end_idx =  rfi->exp_idx;
499 +               else
500 +                       end_idx =  exp_idx;
501 +
502 +               brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
503 +                                            &reorder_list);
504 +               __skb_queue_tail(&reorder_list, pkt);
505 +               /* set the new expected idx */
506 +               rfi->exp_idx = exp_idx;
507 +       }
508 +netif_rx:
509 +       skb_queue_walk_safe(&reorder_list, pkt, pnext) {
510 +               __skb_unlink(pkt, &reorder_list);
511 +               brcmf_netif_rx(ifp, pkt, false);
512 +       }
513 +}
514 +
515  void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
516  {
517         struct brcmf_skb_reorder_data *rd;
518 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
519 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
520 @@ -29,5 +29,6 @@ void brcmf_fws_add_interface(struct brcm
521  void brcmf_fws_del_interface(struct brcmf_if *ifp);
522  void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
523  void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked);
524 +void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb);
525  
526  #endif /* FWSIGNAL_H_ */
527 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
528 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
529 @@ -527,6 +527,9 @@ static int brcmf_msgbuf_hdrpull(struct b
530         return -ENODEV;
531  }
532  
533 +static void brcmf_msgbuf_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)
534 +{
535 +}
536  
537  static void
538  brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid)
539 @@ -1466,6 +1469,7 @@ int brcmf_proto_msgbuf_attach(struct brc
540         drvr->proto->configure_addr_mode = brcmf_msgbuf_configure_addr_mode;
541         drvr->proto->delete_peer = brcmf_msgbuf_delete_peer;
542         drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer;
543 +       drvr->proto->rxreorder = brcmf_msgbuf_rxreorder;
544         drvr->proto->pd = msgbuf;
545  
546         init_waitqueue_head(&msgbuf->ioctl_resp_wait);
547 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
548 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
549 @@ -22,6 +22,9 @@ enum proto_addr_mode {
550         ADDR_DIRECT
551  };
552  
553 +struct brcmf_skb_reorder_data {
554 +       u8 *reorder;
555 +};
556  
557  struct brcmf_proto {
558         int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws,
559 @@ -38,6 +41,7 @@ struct brcmf_proto {
560                             u8 peer[ETH_ALEN]);
561         void (*add_tdls_peer)(struct brcmf_pub *drvr, int ifidx,
562                               u8 peer[ETH_ALEN]);
563 +       void (*rxreorder)(struct brcmf_if *ifp, struct sk_buff *skb);
564         void *pd;
565  };
566  
567 @@ -91,6 +95,18 @@ brcmf_proto_add_tdls_peer(struct brcmf_p
568  {
569         drvr->proto->add_tdls_peer(drvr, ifidx, peer);
570  }
571 +static inline bool brcmf_proto_is_reorder_skb(struct sk_buff *skb)
572 +{
573 +       struct brcmf_skb_reorder_data *rd;
574 +
575 +       rd = (struct brcmf_skb_reorder_data *)skb->cb;
576 +       return !!rd->reorder;
577 +}
578  
579 +static inline void
580 +brcmf_proto_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)
581 +{
582 +       ifp->drvr->proto->rxreorder(ifp, skb);
583 +}
584  
585  #endif /* BRCMFMAC_PROTO_H */