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
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.
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>
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
21 +static void brcmf_proto_bcdc_rxreorder(struct brcmf_if *ifp,
22 + struct sk_buff *skb)
24 + brcmf_fws_rxreorder(ifp, skb);
27 int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
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;
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
42 #define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950)
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
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
57 #define BRCMF_BSSIDX_INVALID -1
59 char *brcmf_ifname(struct brcmf_if *ifp)
60 @@ -342,207 +329,11 @@ void brcmf_netif_rx(struct brcmf_if *ifp
64 -static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
66 - struct sk_buff_head *skb_list)
68 - /* initialize return list */
69 - __skb_queue_head_init(skb_list);
71 - if (rfi->pend_pkts == 0) {
72 - brcmf_dbg(INFO, "no packets in reorder queue\n");
77 - if (rfi->pktslots[start]) {
78 - __skb_queue_tail(skb_list, rfi->pktslots[start]);
79 - rfi->pktslots[start] = NULL;
82 - if (start > rfi->max_idx)
84 - } while (start != end);
85 - rfi->pend_pkts -= skb_queue_len(skb_list);
88 -static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data,
89 - struct sk_buff *pkt)
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;
98 - flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
99 - flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
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);
108 - rfi = ifp->drvr->reorder_flows[flow_id];
109 - if (flags & BRCMF_RXREORDER_DEL_FLOW) {
110 - brcmf_dbg(INFO, "flow-%d: delete\n",
114 - brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
116 - brcmf_netif_rx(ifp, pkt, false);
120 - brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
122 - /* add the last packet */
123 - __skb_queue_tail(&reorder_list, pkt);
125 - ifp->drvr->reorder_flows[flow_id] = NULL;
128 - /* from here on we need a flow reorder instance */
130 - buf_size = sizeof(*rfi);
131 - max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
133 - buf_size += (max_idx + 1) * sizeof(pkt);
135 - /* allocate space for flow reorder info */
136 - brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
138 - rfi = kzalloc(buf_size, GFP_ATOMIC);
140 - brcmf_err("failed to alloc buffer\n");
141 - brcmf_netif_rx(ifp, pkt, false);
145 - ifp->drvr->reorder_flows[flow_id] = rfi;
146 - rfi->pktslots = (struct sk_buff **)(rfi+1);
147 - rfi->max_idx = max_idx;
149 - if (flags & BRCMF_RXREORDER_NEW_HOLE) {
150 - if (rfi->pend_pkts) {
151 - brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
154 - WARN_ON(rfi->pend_pkts);
156 - __skb_queue_head_init(&reorder_list);
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;
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];
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;
177 - rfi->pktslots[cur_idx] = pkt;
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);
183 - /* can return now as there is no reorder
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;
194 - rfi->pktslots[cur_idx] = pkt;
197 - /* got the expected one. flush from current to expected
198 - * and update expected
200 - brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
201 - flow_id, cur_idx, exp_idx, rfi->pend_pkts);
203 - rfi->cur_idx = cur_idx;
204 - rfi->exp_idx = exp_idx;
206 - brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
208 - brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
209 - flow_id, skb_queue_len(&reorder_list),
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,
217 - if (flags & BRCMF_RXREORDER_FLUSH_ALL)
218 - end_idx = rfi->exp_idx;
222 - /* flush pkts first */
223 - brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
226 - if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
227 - __skb_queue_tail(&reorder_list, pkt);
229 - rfi->pktslots[cur_idx] = pkt;
232 - rfi->exp_idx = exp_idx;
233 - rfi->cur_idx = cur_idx;
236 - /* explicity window move updating the expected index */
237 - exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
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;
246 - brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
248 - __skb_queue_tail(&reorder_list, pkt);
249 - /* set the new expected idx */
250 - rfi->exp_idx = exp_idx;
253 - skb_queue_walk_safe(&reorder_list, pkt, pnext) {
254 - __skb_unlink(pkt, &reorder_list);
255 - brcmf_netif_rx(ifp, pkt, false);
259 void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt)
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;
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,
272 - rd = (struct brcmf_skb_reorder_data *)skb->cb;
274 - brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
275 + if (brcmf_proto_is_reorder_skb(skb))
276 + brcmf_proto_rxreorder(ifp, skb);
278 brcmf_netif_rx(ifp, skb, handle_evnt);
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 {
286 -struct brcmf_skb_reorder_data {
290 int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp);
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 {
297 #undef BRCMF_FWS_TLV_DEF
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
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
314 * brcmf_fws_tlv_names - array of tlv names.
315 @@ -1614,6 +1627,202 @@ static int brcmf_fws_notify_bcmc_credit_
319 +static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
321 + struct sk_buff_head *skb_list)
323 + /* initialize return list */
324 + __skb_queue_head_init(skb_list);
326 + if (rfi->pend_pkts == 0) {
327 + brcmf_dbg(INFO, "no packets in reorder queue\n");
332 + if (rfi->pktslots[start]) {
333 + __skb_queue_tail(skb_list, rfi->pktslots[start]);
334 + rfi->pktslots[start] = NULL;
337 + if (start > rfi->max_idx)
339 + } while (start != end);
340 + rfi->pend_pkts -= skb_queue_len(skb_list);
343 +void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt)
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;
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];
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);
364 + rfi = ifp->drvr->reorder_flows[flow_id];
365 + if (flags & BRCMF_RXREORDER_DEL_FLOW) {
366 + brcmf_dbg(INFO, "flow-%d: delete\n",
370 + brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
372 + brcmf_netif_rx(ifp, pkt, false);
376 + brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
378 + /* add the last packet */
379 + __skb_queue_tail(&reorder_list, pkt);
381 + ifp->drvr->reorder_flows[flow_id] = NULL;
384 + /* from here on we need a flow reorder instance */
386 + buf_size = sizeof(*rfi);
387 + max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
389 + buf_size += (max_idx + 1) * sizeof(pkt);
391 + /* allocate space for flow reorder info */
392 + brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
394 + rfi = kzalloc(buf_size, GFP_ATOMIC);
396 + brcmf_err("failed to alloc buffer\n");
397 + brcmf_netif_rx(ifp, pkt, false);
401 + ifp->drvr->reorder_flows[flow_id] = rfi;
402 + rfi->pktslots = (struct sk_buff **)(rfi + 1);
403 + rfi->max_idx = max_idx;
405 + if (flags & BRCMF_RXREORDER_NEW_HOLE) {
406 + if (rfi->pend_pkts) {
407 + brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
410 + WARN_ON(rfi->pend_pkts);
412 + __skb_queue_head_init(&reorder_list);
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;
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];
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;
433 + rfi->pktslots[cur_idx] = pkt;
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);
439 + /* can return now as there is no reorder
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;
450 + rfi->pktslots[cur_idx] = pkt;
453 + /* got the expected one. flush from current to expected
454 + * and update expected
456 + brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
457 + flow_id, cur_idx, exp_idx, rfi->pend_pkts);
459 + rfi->cur_idx = cur_idx;
460 + rfi->exp_idx = exp_idx;
462 + brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
464 + brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
465 + flow_id, skb_queue_len(&reorder_list),
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,
473 + if (flags & BRCMF_RXREORDER_FLUSH_ALL)
474 + end_idx = rfi->exp_idx;
478 + /* flush pkts first */
479 + brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
482 + if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
483 + __skb_queue_tail(&reorder_list, pkt);
485 + rfi->pktslots[cur_idx] = pkt;
488 + rfi->exp_idx = exp_idx;
489 + rfi->cur_idx = cur_idx;
492 + /* explicity window move updating the expected index */
493 + exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
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;
502 + brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
504 + __skb_queue_tail(&reorder_list, pkt);
505 + /* set the new expected idx */
506 + rfi->exp_idx = exp_idx;
509 + skb_queue_walk_safe(&reorder_list, pkt, pnext) {
510 + __skb_unlink(pkt, &reorder_list);
511 + brcmf_netif_rx(ifp, pkt, false);
515 void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
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);
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
533 +static void brcmf_msgbuf_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)
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;
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 {
553 +struct brcmf_skb_reorder_data {
558 int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws,
559 @@ -38,6 +41,7 @@ struct brcmf_proto {
561 void (*add_tdls_peer)(struct brcmf_pub *drvr, int ifidx,
563 + void (*rxreorder)(struct brcmf_if *ifp, struct sk_buff *skb);
567 @@ -91,6 +95,18 @@ brcmf_proto_add_tdls_peer(struct brcmf_p
569 drvr->proto->add_tdls_peer(drvr, ifidx, peer);
571 +static inline bool brcmf_proto_is_reorder_skb(struct sk_buff *skb)
573 + struct brcmf_skb_reorder_data *rd;
575 + rd = (struct brcmf_skb_reorder_data *)skb->cb;
576 + return !!rd->reorder;
580 +brcmf_proto_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)
582 + ifp->drvr->proto->rxreorder(ifp, skb);
585 #endif /* BRCMFMAC_PROTO_H */