diff options
Diffstat (limited to 'package/kernel/mac80211/patches/349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch')
-rw-r--r-- | package/kernel/mac80211/patches/349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch | 585 |
1 files changed, 585 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch b/package/kernel/mac80211/patches/349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch new file mode 100644 index 0000000..33b263d --- /dev/null +++ b/package/kernel/mac80211/patches/349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch @@ -0,0 +1,585 @@ +From: Arend van Spriel <arend@broadcom.com> +Date: Mon, 11 Apr 2016 11:35:26 +0200 +Subject: [PATCH] brcmfmac: cleanup ampdu-rx host reorder code + +The code for ampdu-rx host reorder is related to the firmware signalling +supported in BCDC protocol. This change moves the code to fwsignal module. + +Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com> +Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com> +Reviewed-by: Franky Lin <franky.lin@broadcom.com> +Signed-off-by: Arend van Spriel <arend@broadcom.com> +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c +@@ -351,6 +351,12 @@ brcmf_proto_bcdc_add_tdls_peer(struct br + { + } + ++static void brcmf_proto_bcdc_rxreorder(struct brcmf_if *ifp, ++ struct sk_buff *skb) ++{ ++ brcmf_fws_rxreorder(ifp, skb); ++} ++ + int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) + { + struct brcmf_bcdc *bcdc; +@@ -372,6 +378,7 @@ int brcmf_proto_bcdc_attach(struct brcmf + drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode; + drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer; + drvr->proto->add_tdls_peer = brcmf_proto_bcdc_add_tdls_peer; ++ drvr->proto->rxreorder = brcmf_proto_bcdc_rxreorder; + drvr->proto->pd = bcdc; + + drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -40,19 +40,6 @@ + + #define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950) + +-/* AMPDU rx reordering definitions */ +-#define BRCMF_RXREORDER_FLOWID_OFFSET 0 +-#define BRCMF_RXREORDER_MAXIDX_OFFSET 2 +-#define BRCMF_RXREORDER_FLAGS_OFFSET 4 +-#define BRCMF_RXREORDER_CURIDX_OFFSET 6 +-#define BRCMF_RXREORDER_EXPIDX_OFFSET 8 +- +-#define BRCMF_RXREORDER_DEL_FLOW 0x01 +-#define BRCMF_RXREORDER_FLUSH_ALL 0x02 +-#define BRCMF_RXREORDER_CURIDX_VALID 0x04 +-#define BRCMF_RXREORDER_EXPIDX_VALID 0x08 +-#define BRCMF_RXREORDER_NEW_HOLE 0x10 +- + #define BRCMF_BSSIDX_INVALID -1 + + char *brcmf_ifname(struct brcmf_if *ifp) +@@ -342,207 +329,11 @@ void brcmf_netif_rx(struct brcmf_if *ifp + netif_rx_ni(skb); + } + +-static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi, +- u8 start, u8 end, +- struct sk_buff_head *skb_list) +-{ +- /* initialize return list */ +- __skb_queue_head_init(skb_list); +- +- if (rfi->pend_pkts == 0) { +- brcmf_dbg(INFO, "no packets in reorder queue\n"); +- return; +- } +- +- do { +- if (rfi->pktslots[start]) { +- __skb_queue_tail(skb_list, rfi->pktslots[start]); +- rfi->pktslots[start] = NULL; +- } +- start++; +- if (start > rfi->max_idx) +- start = 0; +- } while (start != end); +- rfi->pend_pkts -= skb_queue_len(skb_list); +-} +- +-static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data, +- struct sk_buff *pkt) +-{ +- u8 flow_id, max_idx, cur_idx, exp_idx, end_idx; +- struct brcmf_ampdu_rx_reorder *rfi; +- struct sk_buff_head reorder_list; +- struct sk_buff *pnext; +- u8 flags; +- u32 buf_size; +- +- flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET]; +- flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET]; +- +- /* validate flags and flow id */ +- if (flags == 0xFF) { +- brcmf_err("invalid flags...so ignore this packet\n"); +- brcmf_netif_rx(ifp, pkt, false); +- return; +- } +- +- rfi = ifp->drvr->reorder_flows[flow_id]; +- if (flags & BRCMF_RXREORDER_DEL_FLOW) { +- brcmf_dbg(INFO, "flow-%d: delete\n", +- flow_id); +- +- if (rfi == NULL) { +- brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n", +- flow_id); +- brcmf_netif_rx(ifp, pkt, false); +- return; +- } +- +- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx, +- &reorder_list); +- /* add the last packet */ +- __skb_queue_tail(&reorder_list, pkt); +- kfree(rfi); +- ifp->drvr->reorder_flows[flow_id] = NULL; +- goto netif_rx; +- } +- /* from here on we need a flow reorder instance */ +- if (rfi == NULL) { +- buf_size = sizeof(*rfi); +- max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET]; +- +- buf_size += (max_idx + 1) * sizeof(pkt); +- +- /* allocate space for flow reorder info */ +- brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n", +- flow_id, max_idx); +- rfi = kzalloc(buf_size, GFP_ATOMIC); +- if (rfi == NULL) { +- brcmf_err("failed to alloc buffer\n"); +- brcmf_netif_rx(ifp, pkt, false); +- return; +- } +- +- ifp->drvr->reorder_flows[flow_id] = rfi; +- rfi->pktslots = (struct sk_buff **)(rfi+1); +- rfi->max_idx = max_idx; +- } +- if (flags & BRCMF_RXREORDER_NEW_HOLE) { +- if (rfi->pend_pkts) { +- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, +- rfi->exp_idx, +- &reorder_list); +- WARN_ON(rfi->pend_pkts); +- } else { +- __skb_queue_head_init(&reorder_list); +- } +- rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET]; +- rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET]; +- rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET]; +- rfi->pktslots[rfi->cur_idx] = pkt; +- rfi->pend_pkts++; +- brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n", +- flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts); +- } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) { +- cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET]; +- exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET]; +- +- if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) { +- /* still in the current hole */ +- /* enqueue the current on the buffer chain */ +- if (rfi->pktslots[cur_idx] != NULL) { +- brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n"); +- brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]); +- rfi->pktslots[cur_idx] = NULL; +- } +- rfi->pktslots[cur_idx] = pkt; +- rfi->pend_pkts++; +- rfi->cur_idx = cur_idx; +- brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n", +- flow_id, cur_idx, exp_idx, rfi->pend_pkts); +- +- /* can return now as there is no reorder +- * list to process. +- */ +- return; +- } +- if (rfi->exp_idx == cur_idx) { +- if (rfi->pktslots[cur_idx] != NULL) { +- brcmf_dbg(INFO, "error buffer pending..free it\n"); +- brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]); +- rfi->pktslots[cur_idx] = NULL; +- } +- rfi->pktslots[cur_idx] = pkt; +- rfi->pend_pkts++; +- +- /* got the expected one. flush from current to expected +- * and update expected +- */ +- brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n", +- flow_id, cur_idx, exp_idx, rfi->pend_pkts); +- +- rfi->cur_idx = cur_idx; +- rfi->exp_idx = exp_idx; +- +- brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx, +- &reorder_list); +- brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n", +- flow_id, skb_queue_len(&reorder_list), +- rfi->pend_pkts); +- } else { +- u8 end_idx; +- +- brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n", +- flow_id, flags, rfi->cur_idx, rfi->exp_idx, +- cur_idx, exp_idx); +- if (flags & BRCMF_RXREORDER_FLUSH_ALL) +- end_idx = rfi->exp_idx; +- else +- end_idx = exp_idx; +- +- /* flush pkts first */ +- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx, +- &reorder_list); +- +- if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) { +- __skb_queue_tail(&reorder_list, pkt); +- } else { +- rfi->pktslots[cur_idx] = pkt; +- rfi->pend_pkts++; +- } +- rfi->exp_idx = exp_idx; +- rfi->cur_idx = cur_idx; +- } +- } else { +- /* explicity window move updating the expected index */ +- exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET]; +- +- brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n", +- flow_id, flags, rfi->exp_idx, exp_idx); +- if (flags & BRCMF_RXREORDER_FLUSH_ALL) +- end_idx = rfi->exp_idx; +- else +- end_idx = exp_idx; +- +- brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx, +- &reorder_list); +- __skb_queue_tail(&reorder_list, pkt); +- /* set the new expected idx */ +- rfi->exp_idx = exp_idx; +- } +-netif_rx: +- skb_queue_walk_safe(&reorder_list, pkt, pnext) { +- __skb_unlink(pkt, &reorder_list); +- brcmf_netif_rx(ifp, pkt, false); +- } +-} +- + void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt) + { + struct brcmf_if *ifp; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; +- struct brcmf_skb_reorder_data *rd; + int ret; + + brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb); +@@ -557,9 +348,8 @@ void brcmf_rx_frame(struct device *dev, + return; + } + +- rd = (struct brcmf_skb_reorder_data *)skb->cb; +- if (rd->reorder) +- brcmf_rxreorder_process_info(ifp, rd->reorder, skb); ++ if (brcmf_proto_is_reorder_skb(skb)) ++ brcmf_proto_rxreorder(ifp, skb); + else + brcmf_netif_rx(ifp, skb, handle_evnt); + } +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +@@ -208,10 +208,6 @@ struct brcmf_if { + u8 ipv6addr_idx; + }; + +-struct brcmf_skb_reorder_data { +- u8 *reorder; +-}; +- + int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp); + + /* Return pointer to interface name */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +@@ -92,6 +92,19 @@ enum brcmf_fws_tlv_len { + }; + #undef BRCMF_FWS_TLV_DEF + ++/* AMPDU rx reordering definitions */ ++#define BRCMF_RXREORDER_FLOWID_OFFSET 0 ++#define BRCMF_RXREORDER_MAXIDX_OFFSET 2 ++#define BRCMF_RXREORDER_FLAGS_OFFSET 4 ++#define BRCMF_RXREORDER_CURIDX_OFFSET 6 ++#define BRCMF_RXREORDER_EXPIDX_OFFSET 8 ++ ++#define BRCMF_RXREORDER_DEL_FLOW 0x01 ++#define BRCMF_RXREORDER_FLUSH_ALL 0x02 ++#define BRCMF_RXREORDER_CURIDX_VALID 0x04 ++#define BRCMF_RXREORDER_EXPIDX_VALID 0x08 ++#define BRCMF_RXREORDER_NEW_HOLE 0x10 ++ + #ifdef DEBUG + /* + * brcmf_fws_tlv_names - array of tlv names. +@@ -1614,6 +1627,202 @@ static int brcmf_fws_notify_bcmc_credit_ + return 0; + } + ++static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi, ++ u8 start, u8 end, ++ struct sk_buff_head *skb_list) ++{ ++ /* initialize return list */ ++ __skb_queue_head_init(skb_list); ++ ++ if (rfi->pend_pkts == 0) { ++ brcmf_dbg(INFO, "no packets in reorder queue\n"); ++ return; ++ } ++ ++ do { ++ if (rfi->pktslots[start]) { ++ __skb_queue_tail(skb_list, rfi->pktslots[start]); ++ rfi->pktslots[start] = NULL; ++ } ++ start++; ++ if (start > rfi->max_idx) ++ start = 0; ++ } while (start != end); ++ rfi->pend_pkts -= skb_queue_len(skb_list); ++} ++ ++void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt) ++{ ++ u8 *reorder_data; ++ u8 flow_id, max_idx, cur_idx, exp_idx, end_idx; ++ struct brcmf_ampdu_rx_reorder *rfi; ++ struct sk_buff_head reorder_list; ++ struct sk_buff *pnext; ++ u8 flags; ++ u32 buf_size; ++ ++ reorder_data = ((struct brcmf_skb_reorder_data *)pkt->cb)->reorder; ++ flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET]; ++ flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET]; ++ ++ /* validate flags and flow id */ ++ if (flags == 0xFF) { ++ brcmf_err("invalid flags...so ignore this packet\n"); ++ brcmf_netif_rx(ifp, pkt, false); ++ return; ++ } ++ ++ rfi = ifp->drvr->reorder_flows[flow_id]; ++ if (flags & BRCMF_RXREORDER_DEL_FLOW) { ++ brcmf_dbg(INFO, "flow-%d: delete\n", ++ flow_id); ++ ++ if (rfi == NULL) { ++ brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n", ++ flow_id); ++ brcmf_netif_rx(ifp, pkt, false); ++ return; ++ } ++ ++ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx, ++ &reorder_list); ++ /* add the last packet */ ++ __skb_queue_tail(&reorder_list, pkt); ++ kfree(rfi); ++ ifp->drvr->reorder_flows[flow_id] = NULL; ++ goto netif_rx; ++ } ++ /* from here on we need a flow reorder instance */ ++ if (rfi == NULL) { ++ buf_size = sizeof(*rfi); ++ max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET]; ++ ++ buf_size += (max_idx + 1) * sizeof(pkt); ++ ++ /* allocate space for flow reorder info */ ++ brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n", ++ flow_id, max_idx); ++ rfi = kzalloc(buf_size, GFP_ATOMIC); ++ if (rfi == NULL) { ++ brcmf_err("failed to alloc buffer\n"); ++ brcmf_netif_rx(ifp, pkt, false); ++ return; ++ } ++ ++ ifp->drvr->reorder_flows[flow_id] = rfi; ++ rfi->pktslots = (struct sk_buff **)(rfi + 1); ++ rfi->max_idx = max_idx; ++ } ++ if (flags & BRCMF_RXREORDER_NEW_HOLE) { ++ if (rfi->pend_pkts) { ++ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, ++ rfi->exp_idx, ++ &reorder_list); ++ WARN_ON(rfi->pend_pkts); ++ } else { ++ __skb_queue_head_init(&reorder_list); ++ } ++ rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET]; ++ rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET]; ++ rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET]; ++ rfi->pktslots[rfi->cur_idx] = pkt; ++ rfi->pend_pkts++; ++ brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n", ++ flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts); ++ } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) { ++ cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET]; ++ exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET]; ++ ++ if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) { ++ /* still in the current hole */ ++ /* enqueue the current on the buffer chain */ ++ if (rfi->pktslots[cur_idx] != NULL) { ++ brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n"); ++ brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]); ++ rfi->pktslots[cur_idx] = NULL; ++ } ++ rfi->pktslots[cur_idx] = pkt; ++ rfi->pend_pkts++; ++ rfi->cur_idx = cur_idx; ++ brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n", ++ flow_id, cur_idx, exp_idx, rfi->pend_pkts); ++ ++ /* can return now as there is no reorder ++ * list to process. ++ */ ++ return; ++ } ++ if (rfi->exp_idx == cur_idx) { ++ if (rfi->pktslots[cur_idx] != NULL) { ++ brcmf_dbg(INFO, "error buffer pending..free it\n"); ++ brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]); ++ rfi->pktslots[cur_idx] = NULL; ++ } ++ rfi->pktslots[cur_idx] = pkt; ++ rfi->pend_pkts++; ++ ++ /* got the expected one. flush from current to expected ++ * and update expected ++ */ ++ brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n", ++ flow_id, cur_idx, exp_idx, rfi->pend_pkts); ++ ++ rfi->cur_idx = cur_idx; ++ rfi->exp_idx = exp_idx; ++ ++ brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx, ++ &reorder_list); ++ brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n", ++ flow_id, skb_queue_len(&reorder_list), ++ rfi->pend_pkts); ++ } else { ++ u8 end_idx; ++ ++ brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n", ++ flow_id, flags, rfi->cur_idx, rfi->exp_idx, ++ cur_idx, exp_idx); ++ if (flags & BRCMF_RXREORDER_FLUSH_ALL) ++ end_idx = rfi->exp_idx; ++ else ++ end_idx = exp_idx; ++ ++ /* flush pkts first */ ++ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx, ++ &reorder_list); ++ ++ if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) { ++ __skb_queue_tail(&reorder_list, pkt); ++ } else { ++ rfi->pktslots[cur_idx] = pkt; ++ rfi->pend_pkts++; ++ } ++ rfi->exp_idx = exp_idx; ++ rfi->cur_idx = cur_idx; ++ } ++ } else { ++ /* explicity window move updating the expected index */ ++ exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET]; ++ ++ brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n", ++ flow_id, flags, rfi->exp_idx, exp_idx); ++ if (flags & BRCMF_RXREORDER_FLUSH_ALL) ++ end_idx = rfi->exp_idx; ++ else ++ end_idx = exp_idx; ++ ++ brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx, ++ &reorder_list); ++ __skb_queue_tail(&reorder_list, pkt); ++ /* set the new expected idx */ ++ rfi->exp_idx = exp_idx; ++ } ++netif_rx: ++ skb_queue_walk_safe(&reorder_list, pkt, pnext) { ++ __skb_unlink(pkt, &reorder_list); ++ brcmf_netif_rx(ifp, pkt, false); ++ } ++} ++ + void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb) + { + struct brcmf_skb_reorder_data *rd; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h +@@ -29,5 +29,6 @@ void brcmf_fws_add_interface(struct brcm + void brcmf_fws_del_interface(struct brcmf_if *ifp); + void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb); + void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked); ++void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb); + + #endif /* FWSIGNAL_H_ */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +@@ -527,6 +527,9 @@ static int brcmf_msgbuf_hdrpull(struct b + return -ENODEV; + } + ++static void brcmf_msgbuf_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb) ++{ ++} + + static void + brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid) +@@ -1466,6 +1469,7 @@ int brcmf_proto_msgbuf_attach(struct brc + drvr->proto->configure_addr_mode = brcmf_msgbuf_configure_addr_mode; + drvr->proto->delete_peer = brcmf_msgbuf_delete_peer; + drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer; ++ drvr->proto->rxreorder = brcmf_msgbuf_rxreorder; + drvr->proto->pd = msgbuf; + + init_waitqueue_head(&msgbuf->ioctl_resp_wait); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h +@@ -22,6 +22,9 @@ enum proto_addr_mode { + ADDR_DIRECT + }; + ++struct brcmf_skb_reorder_data { ++ u8 *reorder; ++}; + + struct brcmf_proto { + int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, +@@ -38,6 +41,7 @@ struct brcmf_proto { + u8 peer[ETH_ALEN]); + void (*add_tdls_peer)(struct brcmf_pub *drvr, int ifidx, + u8 peer[ETH_ALEN]); ++ void (*rxreorder)(struct brcmf_if *ifp, struct sk_buff *skb); + void *pd; + }; + +@@ -91,6 +95,18 @@ brcmf_proto_add_tdls_peer(struct brcmf_p + { + drvr->proto->add_tdls_peer(drvr, ifidx, peer); + } ++static inline bool brcmf_proto_is_reorder_skb(struct sk_buff *skb) ++{ ++ struct brcmf_skb_reorder_data *rd; ++ ++ rd = (struct brcmf_skb_reorder_data *)skb->cb; ++ return !!rd->reorder; ++} + ++static inline void ++brcmf_proto_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb) ++{ ++ ifp->drvr->proto->rxreorder(ifp, skb); ++} + + #endif /* BRCMFMAC_PROTO_H */ |