From 28ac2258e5abcb3b3dc442d384f29bfcd4def4b3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 27 Sep 2016 22:02:08 +0000 Subject: [PATCH] mac80211: brcmfmac: backport patches that were skipped previously #2 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki SVN-Revision: 49406 --- ...cmfmac-Remove-waitqueue_active-check.patch | 54 ++ ...-brcmfmac-uninitialized-ret-variable.patch | 21 + ...o-remove-unused-variable-retry_limit.patch | 24 + ...-unnecessary-variable-initialisation.patch | 26 + ...lear-eventmask-array-before-using-it.patch | 27 + ...ac-fix-clearing-wowl-wake-indicators.patch | 27 + ...efault-boardrev-in-nvram-data-if-mi.patch} | 0 ...2p-scan-abort-null-pointer-exception.patch | 29 + ...fmac-screening-firmware-event-packet.patch | 297 +++++++++ ...c-cleanup-ampdu-rx-host-reorder-code.patch | 585 ++++++++++++++++++ ...vise-handling-events-in-receive-path.patch | 139 +++++ ...common-function-for-handling-brcmf_p.patch | 88 +++ ...work-function-picking-free-BSS-index.patch | 4 +- ...ld-storing-control-channel-to-the-st.patch | 6 +- ...upport-get_channel-cfg80211-callback.patch | 4 +- ...etting-AP-channel-with-new-firmwares.patch | 12 +- ...emove-interface-on-link-down-firmwar.patch | 4 +- ...c-drop-unused-pm_block-vif-attribute.patch | 6 +- ...y-simplify-building-interface-combin.patch | 10 +- ...kup-when-removing-P2P-interface-afte.patch | 16 +- ...st-char-for-interface-name-in-brcmf_.patch | 4 +- ...espect-hidden_ssid-for-AP-interfaces.patch | 4 +- ...-stopping-netdev-queue-when-bus-clog.patch | 2 +- ...fmac-add-missing-eth_type_trans-call.patch | 26 + ...-register-wiphy-s-during-module_init.patch | 2 +- 25 files changed, 1380 insertions(+), 37 deletions(-) create mode 100644 package/kernel/mac80211/patches/345-brcmfmac-Remove-waitqueue_active-check.patch create mode 100644 package/kernel/mac80211/patches/346-brcmfmac-uninitialized-ret-variable.patch create mode 100644 package/kernel/mac80211/patches/347-brcmfmac-sdio-remove-unused-variable-retry_limit.patch create mode 100644 package/kernel/mac80211/patches/348-brcmfmac-Delete-unnecessary-variable-initialisation.patch create mode 100644 package/kernel/mac80211/patches/349-0001-brcmfmac-clear-eventmask-array-before-using-it.patch create mode 100644 package/kernel/mac80211/patches/349-0002-brcmfmac-fix-clearing-wowl-wake-indicators.patch rename package/kernel/mac80211/patches/{345-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch => 349-0003-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch} (100%) create mode 100644 package/kernel/mac80211/patches/349-0004-brcmfmac-fix-p2p-scan-abort-null-pointer-exception.patch create mode 100644 package/kernel/mac80211/patches/349-0005-brcmfmac-screening-firmware-event-packet.patch create mode 100644 package/kernel/mac80211/patches/349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch create mode 100644 package/kernel/mac80211/patches/349-0007-brcmfmac-revise-handling-events-in-receive-path.patch create mode 100644 package/kernel/mac80211/patches/349-0008-brcmfmac-create-common-function-for-handling-brcmf_p.patch create mode 100644 package/kernel/mac80211/patches/860-brcmfmac-add-missing-eth_type_trans-call.patch diff --git a/package/kernel/mac80211/patches/345-brcmfmac-Remove-waitqueue_active-check.patch b/package/kernel/mac80211/patches/345-brcmfmac-Remove-waitqueue_active-check.patch new file mode 100644 index 0000000000..39f438321e --- /dev/null +++ b/package/kernel/mac80211/patches/345-brcmfmac-Remove-waitqueue_active-check.patch @@ -0,0 +1,54 @@ +From: Hui Wang +Date: Wed, 9 Mar 2016 15:25:26 +0800 +Subject: [PATCH] brcmfmac: Remove waitqueue_active check + +We met a problem of pm_suspend when repeated closing/opening the lid +on a Lenovo laptop (1/20 reproduce rate), below is the log: + +[ 199.735876] PM: Entering mem sleep +[ 199.750516] e1000e: EEE TX LPI TIMER: 00000011 +[ 199.856638] Trying to free nonexistent resource <000000000000d000-000000000000d0ff> +[ 201.753566] brcmfmac: brcmf_pcie_suspend: Timeout on response for entering D3 substate +[ 201.753581] pci_legacy_suspend(): brcmf_pcie_suspend+0x0/0x1f0 [brcmfmac] returns -5 +[ 201.753585] dpm_run_callback(): pci_pm_suspend+0x0/0x160 returns -5 +[ 201.753589] PM: Device 0000:04:00.0 failed to suspend async: error -5 + +Through debugging, we found when problem happens, it is not the device +fails to enter D3, but the signal D3_ACK comes too early to pass the +waitqueue_active() check. + +Just like this: +brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D3_INFORM); +// signal is triggered here +wait_event_timeout(devinfo->mbdata_resp_wait, devinfo->mbdata_completed, + BRCMF_PCIE_MBDATA_TIMEOUT); + +So far I think it is safe to remove waitqueue_active check since there +is only one place to trigger this signal (sending +BRCMF_H2D_HOST_D3_INFORM). And it is not a problem calling wake_up +event earlier than calling wait_event. + +Cc: Brett Rudley +Cc: Hante Meuleman +Cc: Franky (Zhenhui) Lin +Cc: Pieter-Paul Giesberts +Cc: Arend van Spriel +Signed-off-by: Hui Wang +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -677,10 +677,8 @@ static void brcmf_pcie_handle_mb_data(st + brcmf_dbg(PCIE, "D2H_MB_DATA: DEEP SLEEP EXIT\n"); + if (dtoh_mb_data & BRCMF_D2H_DEV_D3_ACK) { + brcmf_dbg(PCIE, "D2H_MB_DATA: D3 ACK\n"); +- if (waitqueue_active(&devinfo->mbdata_resp_wait)) { +- devinfo->mbdata_completed = true; +- wake_up(&devinfo->mbdata_resp_wait); +- } ++ devinfo->mbdata_completed = true; ++ wake_up(&devinfo->mbdata_resp_wait); + } + } + diff --git a/package/kernel/mac80211/patches/346-brcmfmac-uninitialized-ret-variable.patch b/package/kernel/mac80211/patches/346-brcmfmac-uninitialized-ret-variable.patch new file mode 100644 index 0000000000..3c9ed425da --- /dev/null +++ b/package/kernel/mac80211/patches/346-brcmfmac-uninitialized-ret-variable.patch @@ -0,0 +1,21 @@ +From: Dan Carpenter +Date: Tue, 15 Mar 2016 10:06:10 +0300 +Subject: [PATCH] brcmfmac: uninitialized "ret" variable + +There is an error path where "ret" isn't initialized. + +Signed-off-by: Dan Carpenter +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +@@ -250,7 +250,7 @@ static int brcmf_sdiod_request_data(stru + u32 addr, u8 regsz, void *data, bool write) + { + struct sdio_func *func; +- int ret; ++ int ret = -EINVAL; + + brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", + write, fn, addr, regsz); diff --git a/package/kernel/mac80211/patches/347-brcmfmac-sdio-remove-unused-variable-retry_limit.patch b/package/kernel/mac80211/patches/347-brcmfmac-sdio-remove-unused-variable-retry_limit.patch new file mode 100644 index 0000000000..d1deb6ee5c --- /dev/null +++ b/package/kernel/mac80211/patches/347-brcmfmac-sdio-remove-unused-variable-retry_limit.patch @@ -0,0 +1,24 @@ +From: Colin Ian King +Date: Sun, 20 Mar 2016 17:34:52 +0000 +Subject: [PATCH] brcmfmac: sdio: remove unused variable retry_limit + +retry_limit has never been used during the life of this driver, so +we may as well remove it as it is redundant. + +Signed-off-by: Colin Ian King +Reviewed-by: Julian Calaby +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -535,9 +535,6 @@ static int qcount[NUMPRIO]; + + #define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL) + +-/* Retry count for register access failures */ +-static const uint retry_limit = 2; +- + /* Limit on rounding up frames */ + static const uint max_roundup = 512; + diff --git a/package/kernel/mac80211/patches/348-brcmfmac-Delete-unnecessary-variable-initialisation.patch b/package/kernel/mac80211/patches/348-brcmfmac-Delete-unnecessary-variable-initialisation.patch new file mode 100644 index 0000000000..d399b264ea --- /dev/null +++ b/package/kernel/mac80211/patches/348-brcmfmac-Delete-unnecessary-variable-initialisation.patch @@ -0,0 +1,26 @@ +From: Markus Elfring +Date: Fri, 18 Mar 2016 13:23:24 +1100 +Subject: [PATCH] brcmfmac: Delete unnecessary variable initialisation + +In brcmf_sdio_download_firmware(), bcmerror is set by the call to +brcmf_sdio_download_code_file(), before it's checked in the following +line. + +Signed-off-by: Markus Elfring +Acked-by: Arend van Spriel +[Rewrote commit message] +Signed-off-by: Julian Calaby +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -3258,7 +3258,7 @@ static int brcmf_sdio_download_firmware( + const struct firmware *fw, + void *nvram, u32 nvlen) + { +- int bcmerror = -EFAULT; ++ int bcmerror; + u32 rstvec; + + sdio_claim_host(bus->sdiodev->func[1]); diff --git a/package/kernel/mac80211/patches/349-0001-brcmfmac-clear-eventmask-array-before-using-it.patch b/package/kernel/mac80211/patches/349-0001-brcmfmac-clear-eventmask-array-before-using-it.patch new file mode 100644 index 0000000000..0acb4faaf1 --- /dev/null +++ b/package/kernel/mac80211/patches/349-0001-brcmfmac-clear-eventmask-array-before-using-it.patch @@ -0,0 +1,27 @@ +From: Hante Meuleman +Date: Mon, 11 Apr 2016 11:35:21 +0200 +Subject: [PATCH] brcmfmac: clear eventmask array before using it + +When the event_msgs iovar is set an array is used to configure the +enabled events. This arrays needs to nulled before configuring +otherwise unhandled events will be enabled. This solves a problem +where in case of wowl the host got woken by an incorrectly enabled +event. + +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Arend Van Spriel +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +@@ -371,6 +371,7 @@ int brcmf_fweh_activate_events(struct br + int i, err; + s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + ++ memset(eventmask, 0, sizeof(eventmask)); + for (i = 0; i < BRCMF_E_LAST; i++) { + if (ifp->drvr->fweh.evt_handler[i]) { + brcmf_dbg(EVENT, "enable event %s\n", diff --git a/package/kernel/mac80211/patches/349-0002-brcmfmac-fix-clearing-wowl-wake-indicators.patch b/package/kernel/mac80211/patches/349-0002-brcmfmac-fix-clearing-wowl-wake-indicators.patch new file mode 100644 index 0000000000..8d3067890c --- /dev/null +++ b/package/kernel/mac80211/patches/349-0002-brcmfmac-fix-clearing-wowl-wake-indicators.patch @@ -0,0 +1,27 @@ +From: Hante Meuleman +Date: Mon, 11 Apr 2016 11:35:22 +0200 +Subject: [PATCH] brcmfmac: fix clearing wowl wake indicators + +Newer firmwares require the usage of the wowl wakeind struct as size +for the iovar to clear the wake indicators. Older firmwares do not +care, so change the used size. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -3608,7 +3608,8 @@ static void brcmf_configure_wowl(struct + if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) + wowl_config |= BRCMF_WOWL_UNASSOC; + +- brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear", strlen("clear")); ++ brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear", ++ sizeof(struct brcmf_wowl_wakeind_le)); + brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config); + brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1); + brcmf_bus_wowl_config(cfg->pub->bus_if, true); diff --git a/package/kernel/mac80211/patches/345-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch b/package/kernel/mac80211/patches/349-0003-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch similarity index 100% rename from package/kernel/mac80211/patches/345-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch rename to package/kernel/mac80211/patches/349-0003-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch diff --git a/package/kernel/mac80211/patches/349-0004-brcmfmac-fix-p2p-scan-abort-null-pointer-exception.patch b/package/kernel/mac80211/patches/349-0004-brcmfmac-fix-p2p-scan-abort-null-pointer-exception.patch new file mode 100644 index 0000000000..ed0c83f9bb --- /dev/null +++ b/package/kernel/mac80211/patches/349-0004-brcmfmac-fix-p2p-scan-abort-null-pointer-exception.patch @@ -0,0 +1,29 @@ +From: Hante Meuleman +Date: Mon, 11 Apr 2016 11:35:24 +0200 +Subject: [PATCH] brcmfmac: fix p2p scan abort null pointer exception + +When p2p connection setup is performed without having ever done an +escan a null pointer exception can occur. This is because the ifp +to abort scanning is taken from escan struct while it was never +initialized. Fix this by using the primary ifp for scan abort. The +abort should still be performed and all scan related commands are +performed on primary ifp. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +@@ -1266,7 +1266,7 @@ static void + brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg) + { + struct brcmf_p2p_info *p2p = &cfg->p2p; +- struct brcmf_if *ifp = cfg->escan_info.ifp; ++ struct brcmf_if *ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; + + if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) && + (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) || diff --git a/package/kernel/mac80211/patches/349-0005-brcmfmac-screening-firmware-event-packet.patch b/package/kernel/mac80211/patches/349-0005-brcmfmac-screening-firmware-event-packet.patch new file mode 100644 index 0000000000..4d26404f51 --- /dev/null +++ b/package/kernel/mac80211/patches/349-0005-brcmfmac-screening-firmware-event-packet.patch @@ -0,0 +1,297 @@ +From: Franky Lin +Date: Mon, 11 Apr 2016 11:35:25 +0200 +Subject: [PATCH] brcmfmac: screening firmware event packet + +Firmware uses asynchronized events as a communication method to the +host. The event packets are marked as ETH_P_LINK_CTL protocol type. For +SDIO and PCIe bus, this kind of packets are delivered through virtual +event channel not data channel. This patch adds a screening logic to +make sure the event handler only processes the events coming from the +correct channel. + +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +@@ -216,7 +216,9 @@ bool brcmf_c_prec_enq(struct device *dev + int prec); + + /* Receive frame for delivery to OS. Callee disposes of rxp. */ +-void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp); ++void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_evnt); ++/* Receive async event packet from firmware. Callee disposes of rxp. */ ++void brcmf_rx_event(struct device *dev, struct sk_buff *rxp); + + /* Indication from bus module regarding presence/insertion of dongle. */ + int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -311,16 +311,17 @@ void brcmf_txflowblock(struct device *de + brcmf_fws_bus_blocked(drvr, state); + } + +-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) ++void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb, ++ bool handle_event) + { +- skb->dev = ifp->ndev; +- skb->protocol = eth_type_trans(skb, skb->dev); ++ skb->protocol = eth_type_trans(skb, ifp->ndev); + + if (skb->pkt_type == PACKET_MULTICAST) + ifp->stats.multicast++; + + /* Process special event packets */ +- brcmf_fweh_process_skb(ifp->drvr, skb); ++ if (handle_event) ++ brcmf_fweh_process_skb(ifp->drvr, skb); + + if (!(ifp->ndev->flags & IFF_UP)) { + brcmu_pkt_buf_free_skb(skb); +@@ -381,7 +382,7 @@ static void brcmf_rxreorder_process_info + /* validate flags and flow id */ + if (flags == 0xFF) { + brcmf_err("invalid flags...so ignore this packet\n"); +- brcmf_netif_rx(ifp, pkt); ++ brcmf_netif_rx(ifp, pkt, false); + return; + } + +@@ -393,7 +394,7 @@ static void brcmf_rxreorder_process_info + if (rfi == NULL) { + brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n", + flow_id); +- brcmf_netif_rx(ifp, pkt); ++ brcmf_netif_rx(ifp, pkt, false); + return; + } + +@@ -418,7 +419,7 @@ static void brcmf_rxreorder_process_info + rfi = kzalloc(buf_size, GFP_ATOMIC); + if (rfi == NULL) { + brcmf_err("failed to alloc buffer\n"); +- brcmf_netif_rx(ifp, pkt); ++ brcmf_netif_rx(ifp, pkt, false); + return; + } + +@@ -532,11 +533,11 @@ static void brcmf_rxreorder_process_info + netif_rx: + skb_queue_walk_safe(&reorder_list, pkt, pnext) { + __skb_unlink(pkt, &reorder_list); +- brcmf_netif_rx(ifp, pkt); ++ brcmf_netif_rx(ifp, pkt, false); + } + } + +-void brcmf_rx_frame(struct device *dev, struct sk_buff *skb) ++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); +@@ -560,7 +561,32 @@ void brcmf_rx_frame(struct device *dev, + if (rd->reorder) + brcmf_rxreorder_process_info(ifp, rd->reorder, skb); + else +- brcmf_netif_rx(ifp, skb); ++ brcmf_netif_rx(ifp, skb, handle_evnt); ++} ++ ++void brcmf_rx_event(struct device *dev, struct sk_buff *skb) ++{ ++ struct brcmf_if *ifp; ++ struct brcmf_bus *bus_if = dev_get_drvdata(dev); ++ struct brcmf_pub *drvr = bus_if->drvr; ++ int ret; ++ ++ brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb); ++ ++ /* process and remove protocol-specific header */ ++ ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp); ++ ++ if (ret || !ifp || !ifp->ndev) { ++ if (ret != -ENODATA && ifp) ++ ifp->stats.rx_errors++; ++ brcmu_pkt_buf_free_skb(skb); ++ return; ++ } ++ ++ skb->protocol = eth_type_trans(skb, ifp->ndev); ++ ++ brcmf_fweh_process_skb(ifp->drvr, skb); ++ brcmu_pkt_buf_free_skb(skb); + } + + void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success) +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +@@ -225,7 +225,8 @@ int brcmf_get_next_free_bsscfgidx(struct + void brcmf_txflowblock_if(struct brcmf_if *ifp, + enum brcmf_netif_stop_reason reason, bool state); + void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); +-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb); ++void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb, ++ bool handle_event); + void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on); + int __init brcmf_core_init(void); + void __exit brcmf_core_exit(void); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +@@ -20,6 +20,7 @@ + + #include + #include ++#include + + #include + #include +@@ -1075,28 +1076,13 @@ static void brcmf_msgbuf_rxbuf_event_pos + } + + +-static void +-brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb, +- u8 ifidx) +-{ +- struct brcmf_if *ifp; +- +- ifp = brcmf_get_ifp(msgbuf->drvr, ifidx); +- if (!ifp || !ifp->ndev) { +- brcmf_err("Received pkt for invalid ifidx %d\n", ifidx); +- brcmu_pkt_buf_free_skb(skb); +- return; +- } +- brcmf_netif_rx(ifp, skb); +-} +- +- + static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf) + { + struct msgbuf_rx_event *event; + u32 idx; + u16 buflen; + struct sk_buff *skb; ++ struct brcmf_if *ifp; + + event = (struct msgbuf_rx_event *)buf; + idx = le32_to_cpu(event->msg.request_id); +@@ -1116,7 +1102,19 @@ static void brcmf_msgbuf_process_event(s + + skb_trim(skb, buflen); + +- brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx); ++ ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx); ++ if (!ifp || !ifp->ndev) { ++ brcmf_err("Received pkt for invalid ifidx %d\n", ++ event->msg.ifidx); ++ goto exit; ++ } ++ ++ skb->protocol = eth_type_trans(skb, ifp->ndev); ++ ++ brcmf_fweh_process_skb(ifp->drvr, skb); ++ ++exit: ++ brcmu_pkt_buf_free_skb(skb); + } + + +@@ -1128,6 +1126,7 @@ brcmf_msgbuf_process_rx_complete(struct + u16 data_offset; + u16 buflen; + u32 idx; ++ struct brcmf_if *ifp; + + brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1); + +@@ -1148,7 +1147,14 @@ brcmf_msgbuf_process_rx_complete(struct + + skb_trim(skb, buflen); + +- brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx); ++ ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx); ++ if (!ifp || !ifp->ndev) { ++ brcmf_err("Received pkt for invalid ifidx %d\n", ++ rx_complete->msg.ifidx); ++ brcmu_pkt_buf_free_skb(skb); ++ return; ++ } ++ brcmf_netif_rx(ifp, skb, false); + } + + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -1294,6 +1294,17 @@ static inline u8 brcmf_sdio_getdatoffset + return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT); + } + ++static inline bool brcmf_sdio_fromevntchan(u8 *swheader) ++{ ++ u32 hdrvalue; ++ u8 ret; ++ ++ hdrvalue = *(u32 *)swheader; ++ ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT); ++ ++ return (ret == SDPCM_EVENT_CHANNEL); ++} ++ + static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header, + struct brcmf_sdio_hdrinfo *rd, + enum brcmf_sdio_frmtype type) +@@ -1641,7 +1652,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf + pfirst->len, pfirst->next, + pfirst->prev); + skb_unlink(pfirst, &bus->glom); +- brcmf_rx_frame(bus->sdiodev->dev, pfirst); ++ if (brcmf_sdio_fromevntchan(pfirst->data)) ++ brcmf_rx_event(bus->sdiodev->dev, pfirst); ++ else ++ brcmf_rx_frame(bus->sdiodev->dev, pfirst, ++ false); + bus->sdcnt.rxglompkts++; + } + +@@ -1967,18 +1982,19 @@ static uint brcmf_sdio_readframes(struct + __skb_trim(pkt, rd->len); + skb_pull(pkt, rd->dat_offset); + ++ if (pkt->len == 0) ++ brcmu_pkt_buf_free_skb(pkt); ++ else if (rd->channel == SDPCM_EVENT_CHANNEL) ++ brcmf_rx_event(bus->sdiodev->dev, pkt); ++ else ++ brcmf_rx_frame(bus->sdiodev->dev, pkt, ++ false); ++ + /* prepare the descriptor for the next read */ + rd->len = rd->len_nxtfrm << 4; + rd->len_nxtfrm = 0; + /* treat all packet as event if we don't know */ + rd->channel = SDPCM_EVENT_CHANNEL; +- +- if (pkt->len == 0) { +- brcmu_pkt_buf_free_skb(pkt); +- continue; +- } +- +- brcmf_rx_frame(bus->sdiodev->dev, pkt); + } + + rxcount = maxframes - rxleft; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +@@ -514,7 +514,7 @@ static void brcmf_usb_rx_complete(struct + + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { + skb_put(skb, urb->actual_length); +- brcmf_rx_frame(devinfo->dev, skb); ++ brcmf_rx_frame(devinfo->dev, skb, true); + brcmf_usb_rx_refill(devinfo, req); + } else { + brcmu_pkt_buf_free_skb(skb); 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 0000000000..33b263df3a --- /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 +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 +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- 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 */ diff --git a/package/kernel/mac80211/patches/349-0007-brcmfmac-revise-handling-events-in-receive-path.patch b/package/kernel/mac80211/patches/349-0007-brcmfmac-revise-handling-events-in-receive-path.patch new file mode 100644 index 0000000000..a43feffe17 --- /dev/null +++ b/package/kernel/mac80211/patches/349-0007-brcmfmac-revise-handling-events-in-receive-path.patch @@ -0,0 +1,139 @@ +From: Arend van Spriel +Date: Mon, 11 Apr 2016 11:35:27 +0200 +Subject: [PATCH] brcmfmac: revise handling events in receive path + +Move event handling out of brcmf_netif_rx() avoiding the need +to pass a flag. This flag is only ever true for USB hosts as +other interface use separate brcmf_rx_event() function. + +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +@@ -216,7 +216,7 @@ bool brcmf_c_prec_enq(struct device *dev + int prec); + + /* Receive frame for delivery to OS. Callee disposes of rxp. */ +-void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_evnt); ++void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_event); + /* Receive async event packet from firmware. Callee disposes of rxp. */ + void brcmf_rx_event(struct device *dev, struct sk_buff *rxp); + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -298,18 +298,11 @@ void brcmf_txflowblock(struct device *de + brcmf_fws_bus_blocked(drvr, state); + } + +-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb, +- bool handle_event) ++void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) + { +- skb->protocol = eth_type_trans(skb, ifp->ndev); +- + if (skb->pkt_type == PACKET_MULTICAST) + ifp->stats.multicast++; + +- /* Process special event packets */ +- if (handle_event) +- brcmf_fweh_process_skb(ifp->drvr, skb); +- + if (!(ifp->ndev->flags & IFF_UP)) { + brcmu_pkt_buf_free_skb(skb); + return; +@@ -329,7 +322,7 @@ void brcmf_netif_rx(struct brcmf_if *ifp + netif_rx_ni(skb); + } + +-void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt) ++void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event) + { + struct brcmf_if *ifp; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); +@@ -348,10 +341,17 @@ void brcmf_rx_frame(struct device *dev, + return; + } + +- if (brcmf_proto_is_reorder_skb(skb)) ++ skb->protocol = eth_type_trans(skb, ifp->ndev); ++ ++ if (brcmf_proto_is_reorder_skb(skb)) { + brcmf_proto_rxreorder(ifp, skb); +- else +- brcmf_netif_rx(ifp, skb, handle_evnt); ++ } else { ++ /* Process special event packets */ ++ if (handle_event) ++ brcmf_fweh_process_skb(ifp->drvr, skb); ++ ++ brcmf_netif_rx(ifp, skb); ++ } + } + + void brcmf_rx_event(struct device *dev, struct sk_buff *skb) +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +@@ -221,8 +221,7 @@ int brcmf_get_next_free_bsscfgidx(struct + void brcmf_txflowblock_if(struct brcmf_if *ifp, + enum brcmf_netif_stop_reason reason, bool state); + void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); +-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb, +- bool handle_event); ++void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb); + void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on); + int __init brcmf_core_init(void); + void __exit brcmf_core_exit(void); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +@@ -1668,7 +1668,7 @@ void brcmf_fws_rxreorder(struct brcmf_if + /* validate flags and flow id */ + if (flags == 0xFF) { + brcmf_err("invalid flags...so ignore this packet\n"); +- brcmf_netif_rx(ifp, pkt, false); ++ brcmf_netif_rx(ifp, pkt); + return; + } + +@@ -1680,7 +1680,7 @@ void brcmf_fws_rxreorder(struct brcmf_if + if (rfi == NULL) { + brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n", + flow_id); +- brcmf_netif_rx(ifp, pkt, false); ++ brcmf_netif_rx(ifp, pkt); + return; + } + +@@ -1705,7 +1705,7 @@ void brcmf_fws_rxreorder(struct brcmf_if + rfi = kzalloc(buf_size, GFP_ATOMIC); + if (rfi == NULL) { + brcmf_err("failed to alloc buffer\n"); +- brcmf_netif_rx(ifp, pkt, false); ++ brcmf_netif_rx(ifp, pkt); + return; + } + +@@ -1819,7 +1819,7 @@ void brcmf_fws_rxreorder(struct brcmf_if + netif_rx: + skb_queue_walk_safe(&reorder_list, pkt, pnext) { + __skb_unlink(pkt, &reorder_list); +- brcmf_netif_rx(ifp, pkt, false); ++ brcmf_netif_rx(ifp, pkt); + } + } + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +@@ -1157,7 +1157,7 @@ brcmf_msgbuf_process_rx_complete(struct + brcmu_pkt_buf_free_skb(skb); + return; + } +- brcmf_netif_rx(ifp, skb, false); ++ brcmf_netif_rx(ifp, skb); + } + + diff --git a/package/kernel/mac80211/patches/349-0008-brcmfmac-create-common-function-for-handling-brcmf_p.patch b/package/kernel/mac80211/patches/349-0008-brcmfmac-create-common-function-for-handling-brcmf_p.patch new file mode 100644 index 0000000000..08ea235fdd --- /dev/null +++ b/package/kernel/mac80211/patches/349-0008-brcmfmac-create-common-function-for-handling-brcmf_p.patch @@ -0,0 +1,88 @@ +From: Arend van Spriel +Date: Mon, 11 Apr 2016 11:35:28 +0200 +Subject: [PATCH] brcmfmac: create common function for handling + brcmf_proto_hdrpull() + +In receive path brcmf_proto_hdrpull() needs to be called and handled +similar in brcmf_rx_frame() and brcmf_rx_event(). Move that duplicated +code in separate function. + +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -322,26 +322,35 @@ void brcmf_netif_rx(struct brcmf_if *ifp + netif_rx_ni(skb); + } + +-void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event) ++static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb, ++ struct brcmf_if **ifp) + { +- struct brcmf_if *ifp; +- struct brcmf_bus *bus_if = dev_get_drvdata(dev); +- struct brcmf_pub *drvr = bus_if->drvr; + int ret; + +- brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb); +- + /* process and remove protocol-specific header */ +- ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp); ++ ret = brcmf_proto_hdrpull(drvr, true, skb, ifp); + +- if (ret || !ifp || !ifp->ndev) { ++ if (ret || !(*ifp) || !(*ifp)->ndev) { + if (ret != -ENODATA && ifp) +- ifp->stats.rx_errors++; ++ (*ifp)->stats.rx_errors++; + brcmu_pkt_buf_free_skb(skb); +- return; ++ return -ENODATA; + } + +- skb->protocol = eth_type_trans(skb, ifp->ndev); ++ skb->protocol = eth_type_trans(skb, (*ifp)->ndev); ++ return 0; ++} ++ ++void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event) ++{ ++ struct brcmf_if *ifp; ++ struct brcmf_bus *bus_if = dev_get_drvdata(dev); ++ struct brcmf_pub *drvr = bus_if->drvr; ++ ++ brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb); ++ ++ if (brcmf_rx_hdrpull(drvr, skb, &ifp)) ++ return; + + if (brcmf_proto_is_reorder_skb(skb)) { + brcmf_proto_rxreorder(ifp, skb); +@@ -359,21 +368,11 @@ void brcmf_rx_event(struct device *dev, + struct brcmf_if *ifp; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; +- int ret; + + brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb); + +- /* process and remove protocol-specific header */ +- ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp); +- +- if (ret || !ifp || !ifp->ndev) { +- if (ret != -ENODATA && ifp) +- ifp->stats.rx_errors++; +- brcmu_pkt_buf_free_skb(skb); ++ if (brcmf_rx_hdrpull(drvr, skb, &ifp)) + return; +- } +- +- skb->protocol = eth_type_trans(skb, ifp->ndev); + + brcmf_fweh_process_skb(ifp->drvr, skb); + brcmu_pkt_buf_free_skb(skb); diff --git a/package/kernel/mac80211/patches/351-0005-brcmfmac-rework-function-picking-free-BSS-index.patch b/package/kernel/mac80211/patches/351-0005-brcmfmac-rework-function-picking-free-BSS-index.patch index f242748723..c602f2272a 100644 --- a/package/kernel/mac80211/patches/351-0005-brcmfmac-rework-function-picking-free-BSS-index.patch +++ b/package/kernel/mac80211/patches/351-0005-brcmfmac-rework-function-picking-free-BSS-index.patch @@ -76,7 +76,7 @@ Signed-off-by: Kalle Valo --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c -@@ -938,30 +938,6 @@ void brcmf_remove_interface(struct brcmf +@@ -753,30 +753,6 @@ void brcmf_remove_interface(struct brcmf brcmf_del_if(ifp->drvr, ifp->bsscfgidx); } @@ -109,7 +109,7 @@ Signed-off-by: Kalle Valo static int brcmf_inetaddr_changed(struct notifier_block *nb, --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h -@@ -221,7 +221,6 @@ int brcmf_net_attach(struct brcmf_if *if +@@ -217,7 +217,6 @@ int brcmf_net_attach(struct brcmf_if *if struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, bool is_p2pdev, char *name, u8 *mac_addr); void brcmf_remove_interface(struct brcmf_if *ifp); diff --git a/package/kernel/mac80211/patches/351-0007-brcmutil-add-field-storing-control-channel-to-the-st.patch b/package/kernel/mac80211/patches/351-0007-brcmutil-add-field-storing-control-channel-to-the-st.patch index 6f064d16ef..a79c9a2e93 100644 --- a/package/kernel/mac80211/patches/351-0007-brcmutil-add-field-storing-control-channel-to-the-st.patch +++ b/package/kernel/mac80211/patches/351-0007-brcmutil-add-field-storing-control-channel-to-the-st.patch @@ -54,7 +54,7 @@ Signed-off-by: Kalle Valo brcmf_dbg(CONN, "capability: %X\n", notify_capability); brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval); brcmf_dbg(CONN, "signal: %d\n", notify_signal); -@@ -5234,7 +5234,7 @@ brcmf_bss_roaming_done(struct brcmf_cfg8 +@@ -5235,7 +5235,7 @@ brcmf_bss_roaming_done(struct brcmf_cfg8 else band = wiphy->bands[IEEE80211_BAND_5GHZ]; @@ -63,7 +63,7 @@ Signed-off-by: Kalle Valo notify_channel = ieee80211_get_channel(wiphy, freq); done: -@@ -5756,14 +5756,15 @@ static int brcmf_construct_chaninfo(stru +@@ -5757,14 +5757,15 @@ static int brcmf_construct_chaninfo(stru channel = band->channels; index = band->n_channels; for (j = 0; j < band->n_channels; j++) { @@ -82,7 +82,7 @@ Signed-off-by: Kalle Valo /* assuming the chanspecs order is HT20, * HT40 upper, HT40 lower, and VHT80. -@@ -5865,7 +5866,7 @@ static int brcmf_enable_bw40_2g(struct b +@@ -5866,7 +5867,7 @@ static int brcmf_enable_bw40_2g(struct b if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40)) continue; for (j = 0; j < band->n_channels; j++) { diff --git a/package/kernel/mac80211/patches/351-0008-brcmfmac-support-get_channel-cfg80211-callback.patch b/package/kernel/mac80211/patches/351-0008-brcmfmac-support-get_channel-cfg80211-callback.patch index 3e16c4bfc7..2c536d178d 100644 --- a/package/kernel/mac80211/patches/351-0008-brcmfmac-support-get_channel-cfg80211-callback.patch +++ b/package/kernel/mac80211/patches/351-0008-brcmfmac-support-get_channel-cfg80211-callback.patch @@ -15,7 +15,7 @@ Signed-off-by: Kalle Valo --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -@@ -4846,6 +4846,68 @@ exit: +@@ -4847,6 +4847,68 @@ exit: return err; } @@ -84,7 +84,7 @@ Signed-off-by: Kalle Valo static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy, struct wireless_dev *wdev, enum nl80211_crit_proto_id proto, -@@ -5008,6 +5070,7 @@ static struct cfg80211_ops brcmf_cfg8021 +@@ -5009,6 +5071,7 @@ static struct cfg80211_ops brcmf_cfg8021 .mgmt_tx = brcmf_cfg80211_mgmt_tx, .remain_on_channel = brcmf_p2p_remain_on_channel, .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, diff --git a/package/kernel/mac80211/patches/351-0010-brcmfmac-fix-setting-AP-channel-with-new-firmwares.patch b/package/kernel/mac80211/patches/351-0010-brcmfmac-fix-setting-AP-channel-with-new-firmwares.patch index bf06a767d4..a2e18a5fe9 100644 --- a/package/kernel/mac80211/patches/351-0010-brcmfmac-fix-setting-AP-channel-with-new-firmwares.patch +++ b/package/kernel/mac80211/patches/351-0010-brcmfmac-fix-setting-AP-channel-with-new-firmwares.patch @@ -32,7 +32,7 @@ Signed-off-by: Kalle Valo --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -@@ -4381,7 +4381,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi +@@ -4382,7 +4382,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi struct brcmf_join_params join_params; enum nl80211_iftype dev_role; struct brcmf_fil_bss_enable_le bss_enable; @@ -41,7 +41,7 @@ Signed-off-by: Kalle Valo bool mbss; int is_11d; -@@ -4457,16 +4457,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi +@@ -4458,16 +4458,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); @@ -59,7 +59,7 @@ Signed-off-by: Kalle Valo if (is_11d != ifp->vif->is_11d) { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, is_11d); -@@ -4514,6 +4506,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi +@@ -4515,6 +4507,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi err = -EINVAL; goto exit; } @@ -68,7 +68,7 @@ Signed-off-by: Kalle Valo if (dev_role == NL80211_IFTYPE_AP) { if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss)) brcmf_fil_iovar_int_set(ifp, "mbss", 1); -@@ -4523,6 +4517,17 @@ brcmf_cfg80211_start_ap(struct wiphy *wi +@@ -4524,6 +4518,17 @@ brcmf_cfg80211_start_ap(struct wiphy *wi brcmf_err("setting AP mode failed %d\n", err); goto exit; } @@ -86,7 +86,7 @@ Signed-off-by: Kalle Valo err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); if (err < 0) { brcmf_err("BRCMF_C_UP error (%d)\n", err); -@@ -4544,7 +4549,13 @@ brcmf_cfg80211_start_ap(struct wiphy *wi +@@ -4545,7 +4550,13 @@ brcmf_cfg80211_start_ap(struct wiphy *wi goto exit; } brcmf_dbg(TRACE, "AP mode configuration complete\n"); @@ -101,7 +101,7 @@ Signed-off-by: Kalle Valo err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le, sizeof(ssid_le)); if (err < 0) { -@@ -4561,7 +4572,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wi +@@ -4562,7 +4573,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wi } brcmf_dbg(TRACE, "GO mode configuration complete\n"); diff --git a/package/kernel/mac80211/patches/351-0011-brcmfmac-don-t-remove-interface-on-link-down-firmwar.patch b/package/kernel/mac80211/patches/351-0011-brcmfmac-don-t-remove-interface-on-link-down-firmwar.patch index 6ef145338c..167e4347d5 100644 --- a/package/kernel/mac80211/patches/351-0011-brcmfmac-don-t-remove-interface-on-link-down-firmwar.patch +++ b/package/kernel/mac80211/patches/351-0011-brcmfmac-don-t-remove-interface-on-link-down-firmwar.patch @@ -41,7 +41,7 @@ Signed-off-by: Kalle Valo --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -@@ -5371,7 +5371,6 @@ brcmf_notify_connect_status_ap(struct br +@@ -5372,7 +5372,6 @@ brcmf_notify_connect_status_ap(struct br struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { @@ -49,7 +49,7 @@ Signed-off-by: Kalle Valo static int generation; u32 event = e->event_code; u32 reason = e->reason; -@@ -5382,8 +5381,6 @@ brcmf_notify_connect_status_ap(struct br +@@ -5383,8 +5382,6 @@ brcmf_notify_connect_status_ap(struct br ndev != cfg_to_ndev(cfg)) { brcmf_dbg(CONN, "AP mode link down\n"); complete(&cfg->vif_disabled); diff --git a/package/kernel/mac80211/patches/351-0017-brcmfmac-drop-unused-pm_block-vif-attribute.patch b/package/kernel/mac80211/patches/351-0017-brcmfmac-drop-unused-pm_block-vif-attribute.patch index f5bacd22db..3b407db355 100644 --- a/package/kernel/mac80211/patches/351-0017-brcmfmac-drop-unused-pm_block-vif-attribute.patch +++ b/package/kernel/mac80211/patches/351-0017-brcmfmac-drop-unused-pm_block-vif-attribute.patch @@ -24,7 +24,7 @@ Signed-off-by: Kalle Valo if (IS_ERR(vif)) return (struct wireless_dev *)vif; -@@ -5097,8 +5097,7 @@ static struct cfg80211_ops brcmf_cfg8021 +@@ -5098,8 +5098,7 @@ static struct cfg80211_ops brcmf_cfg8021 }; struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, @@ -34,7 +34,7 @@ Signed-off-by: Kalle Valo { struct brcmf_cfg80211_vif *vif_walk; struct brcmf_cfg80211_vif *vif; -@@ -5113,8 +5112,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_v +@@ -5114,8 +5113,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_v vif->wdev.wiphy = cfg->wiphy; vif->wdev.iftype = type; @@ -43,7 +43,7 @@ Signed-off-by: Kalle Valo brcmf_init_prof(&vif->profile); if (type == NL80211_IFTYPE_AP) { -@@ -6753,7 +6750,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802 +@@ -6754,7 +6751,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802 init_vif_event(&cfg->vif_event); INIT_LIST_HEAD(&cfg->vif_list); diff --git a/package/kernel/mac80211/patches/351-0019-brcmfmac-slightly-simplify-building-interface-combin.patch b/package/kernel/mac80211/patches/351-0019-brcmfmac-slightly-simplify-building-interface-combin.patch index 7d57f72da2..1b885e0b89 100644 --- a/package/kernel/mac80211/patches/351-0019-brcmfmac-slightly-simplify-building-interface-combin.patch +++ b/package/kernel/mac80211/patches/351-0019-brcmfmac-slightly-simplify-building-interface-combin.patch @@ -23,7 +23,7 @@ Signed-off-by: Kalle Valo --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -@@ -6207,29 +6207,15 @@ static int brcmf_setup_ifmodes(struct wi +@@ -6208,29 +6208,15 @@ static int brcmf_setup_ifmodes(struct wi if (!combo) goto err; @@ -56,7 +56,7 @@ Signed-off-by: Kalle Valo c0_limits[i].max = 1; c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION); if (p2p) { -@@ -6247,6 +6233,7 @@ static int brcmf_setup_ifmodes(struct wi +@@ -6248,6 +6234,7 @@ static int brcmf_setup_ifmodes(struct wi c0_limits[i].max = 1; c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); } @@ -64,7 +64,7 @@ Signed-off-by: Kalle Valo combo[c].max_interfaces = i; combo[c].n_limits = i; combo[c].limits = c0_limits; -@@ -6254,7 +6241,9 @@ static int brcmf_setup_ifmodes(struct wi +@@ -6255,7 +6242,9 @@ static int brcmf_setup_ifmodes(struct wi if (p2p) { c++; i = 0; @@ -75,7 +75,7 @@ Signed-off-by: Kalle Valo p2p_limits[i].max = 1; p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION); p2p_limits[i].max = 1; -@@ -6263,6 +6252,7 @@ static int brcmf_setup_ifmodes(struct wi +@@ -6264,6 +6253,7 @@ static int brcmf_setup_ifmodes(struct wi p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT); p2p_limits[i].max = 1; p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); @@ -83,7 +83,7 @@ Signed-off-by: Kalle Valo combo[c].max_interfaces = i; combo[c].n_limits = i; combo[c].limits = p2p_limits; -@@ -6270,14 +6260,19 @@ static int brcmf_setup_ifmodes(struct wi +@@ -6271,14 +6261,19 @@ static int brcmf_setup_ifmodes(struct wi if (mbss) { c++; diff --git a/package/kernel/mac80211/patches/351-0020-brcmfmac-fix-lockup-when-removing-P2P-interface-afte.patch b/package/kernel/mac80211/patches/351-0020-brcmfmac-fix-lockup-when-removing-P2P-interface-afte.patch index 995688a6b8..0dd88bc7a6 100644 --- a/package/kernel/mac80211/patches/351-0020-brcmfmac-fix-lockup-when-removing-P2P-interface-afte.patch +++ b/package/kernel/mac80211/patches/351-0020-brcmfmac-fix-lockup-when-removing-P2P-interface-afte.patch @@ -29,7 +29,7 @@ Signed-off-by: Kalle Valo --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c -@@ -733,12 +733,16 @@ fail: +@@ -548,12 +548,16 @@ fail: return -EBADE; } @@ -50,7 +50,7 @@ Signed-off-by: Kalle Valo } void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on) -@@ -836,7 +840,7 @@ struct brcmf_if *brcmf_add_if(struct brc +@@ -651,7 +655,7 @@ struct brcmf_if *brcmf_add_if(struct brc brcmf_err("ERROR: netdev:%s already exists\n", ifp->ndev->name); netif_stop_queue(ifp->ndev); @@ -59,7 +59,7 @@ Signed-off-by: Kalle Valo drvr->iflist[bsscfgidx] = NULL; } else { brcmf_dbg(INFO, "netdev:%s ignore IF event\n", -@@ -884,7 +888,8 @@ struct brcmf_if *brcmf_add_if(struct brc +@@ -699,7 +703,8 @@ struct brcmf_if *brcmf_add_if(struct brc return ifp; } @@ -69,7 +69,7 @@ Signed-off-by: Kalle Valo { struct brcmf_if *ifp; -@@ -914,7 +919,7 @@ static void brcmf_del_if(struct brcmf_pu +@@ -729,7 +734,7 @@ static void brcmf_del_if(struct brcmf_pu cancel_work_sync(&ifp->multicast_work); cancel_work_sync(&ifp->ndoffload_work); } @@ -78,7 +78,7 @@ Signed-off-by: Kalle Valo } else { /* Only p2p device interfaces which get dynamically created * end up here. In this case the p2p module should be informed -@@ -928,14 +933,14 @@ static void brcmf_del_if(struct brcmf_pu +@@ -743,14 +748,14 @@ static void brcmf_del_if(struct brcmf_pu } } @@ -95,7 +95,7 @@ Signed-off-by: Kalle Valo } #ifdef CONFIG_INET -@@ -1242,9 +1247,9 @@ fail: +@@ -1057,9 +1062,9 @@ fail: brcmf_fws_deinit(drvr); } if (ifp) @@ -107,7 +107,7 @@ Signed-off-by: Kalle Valo drvr->iflist[0] = NULL; drvr->iflist[1] = NULL; if (drvr->settings->ignore_probe_fail) -@@ -1313,7 +1318,7 @@ void brcmf_detach(struct device *dev) +@@ -1128,7 +1133,7 @@ void brcmf_detach(struct device *dev) /* make sure primary interface removed last */ for (i = BRCMF_MAX_IFS-1; i > -1; i--) @@ -118,7 +118,7 @@ Signed-off-by: Kalle Valo --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h -@@ -220,7 +220,7 @@ struct brcmf_if *brcmf_get_ifp(struct br +@@ -216,7 +216,7 @@ struct brcmf_if *brcmf_get_ifp(struct br int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, bool is_p2pdev, char *name, u8 *mac_addr); diff --git a/package/kernel/mac80211/patches/351-0021-brcmfmac-use-const-char-for-interface-name-in-brcmf_.patch b/package/kernel/mac80211/patches/351-0021-brcmfmac-use-const-char-for-interface-name-in-brcmf_.patch index 21ff7d54e0..24f06c4129 100644 --- a/package/kernel/mac80211/patches/351-0021-brcmfmac-use-const-char-for-interface-name-in-brcmf_.patch +++ b/package/kernel/mac80211/patches/351-0021-brcmfmac-use-const-char-for-interface-name-in-brcmf_.patch @@ -17,7 +17,7 @@ Signed-off-by: Kalle Valo --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c -@@ -823,7 +823,7 @@ fail: +@@ -638,7 +638,7 @@ fail: } struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, @@ -28,7 +28,7 @@ Signed-off-by: Kalle Valo struct net_device *ndev; --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h -@@ -219,7 +219,7 @@ char *brcmf_ifname(struct brcmf_if *ifp) +@@ -215,7 +215,7 @@ char *brcmf_ifname(struct brcmf_if *ifp) struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx); int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, diff --git a/package/kernel/mac80211/patches/351-0026-brcmfmac-respect-hidden_ssid-for-AP-interfaces.patch b/package/kernel/mac80211/patches/351-0026-brcmfmac-respect-hidden_ssid-for-AP-interfaces.patch index 9d64691da7..94ab246413 100644 --- a/package/kernel/mac80211/patches/351-0026-brcmfmac-respect-hidden_ssid-for-AP-interfaces.patch +++ b/package/kernel/mac80211/patches/351-0026-brcmfmac-respect-hidden_ssid-for-AP-interfaces.patch @@ -14,7 +14,7 @@ Signed-off-by: Kalle Valo --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -@@ -4585,6 +4585,15 @@ brcmf_cfg80211_start_ap(struct wiphy *wi +@@ -4586,6 +4586,15 @@ brcmf_cfg80211_start_ap(struct wiphy *wi brcmf_err("SET SSID error (%d)\n", err); goto exit; } @@ -30,7 +30,7 @@ Signed-off-by: Kalle Valo brcmf_dbg(TRACE, "AP mode configuration complete\n"); } else if (dev_role == NL80211_IFTYPE_P2P_GO) { err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); -@@ -4643,6 +4652,10 @@ static int brcmf_cfg80211_stop_ap(struct +@@ -4644,6 +4653,10 @@ static int brcmf_cfg80211_stop_ap(struct return err; } diff --git a/package/kernel/mac80211/patches/351-0027-brcmfmac-restore-stopping-netdev-queue-when-bus-clog.patch b/package/kernel/mac80211/patches/351-0027-brcmfmac-restore-stopping-netdev-queue-when-bus-clog.patch index 0fac3a697d..d360b27f46 100644 --- a/package/kernel/mac80211/patches/351-0027-brcmfmac-restore-stopping-netdev-queue-when-bus-clog.patch +++ b/package/kernel/mac80211/patches/351-0027-brcmfmac-restore-stopping-netdev-queue-when-bus-clog.patch @@ -23,7 +23,7 @@ Signed-off-by: Kalle Valo --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c -@@ -2260,10 +2260,22 @@ void brcmf_fws_bustxfail(struct brcmf_fw +@@ -2469,10 +2469,22 @@ void brcmf_fws_bustxfail(struct brcmf_fw void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked) { struct brcmf_fws_info *fws = drvr->fws; diff --git a/package/kernel/mac80211/patches/860-brcmfmac-add-missing-eth_type_trans-call.patch b/package/kernel/mac80211/patches/860-brcmfmac-add-missing-eth_type_trans-call.patch new file mode 100644 index 0000000000..46227c48dd --- /dev/null +++ b/package/kernel/mac80211/patches/860-brcmfmac-add-missing-eth_type_trans-call.patch @@ -0,0 +1,26 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Subject: [PATCH] brcmfmac: add missing eth_type_trans call +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There are 2 protocols supported by brcmfmac and msgbuf one was missing a +proper skb setup before passing it to the netif. This was triggering +"NULL pointer dereference". + +Fixes: 9c349892ccc9 ("brcmfmac: revise handling events in receive path") +Signed-off-by: Rafał Miłecki +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +@@ -1157,6 +1157,9 @@ brcmf_msgbuf_process_rx_complete(struct + brcmu_pkt_buf_free_skb(skb); + return; + } ++ ++ skb->protocol = eth_type_trans(skb, ifp->ndev); ++ + brcmf_netif_rx(ifp, skb); + } + diff --git a/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch b/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch index 9850e2dad3..ae571c99ab 100644 --- a/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch +++ b/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch @@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c -@@ -1398,6 +1398,7 @@ int __init brcmf_core_init(void) +@@ -1213,6 +1213,7 @@ int __init brcmf_core_init(void) { if (!schedule_work(&brcmf_driver_work)) return -EBUSY; -- 2.30.2