mac80211: brcmfmac: backport patches that were skipped previously #2
authorRafał Miłecki <zajec5@gmail.com>
Tue, 27 Sep 2016 22:02:08 +0000 (22:02 +0000)
committerRafał Miłecki <zajec5@gmail.com>
Tue, 27 Sep 2016 22:02:08 +0000 (22:02 +0000)
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
SVN-Revision: 49406

26 files changed:
package/kernel/mac80211/patches/345-brcmfmac-Remove-waitqueue_active-check.patch [new file with mode: 0644]
package/kernel/mac80211/patches/345-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch [deleted file]
package/kernel/mac80211/patches/346-brcmfmac-uninitialized-ret-variable.patch [new file with mode: 0644]
package/kernel/mac80211/patches/347-brcmfmac-sdio-remove-unused-variable-retry_limit.patch [new file with mode: 0644]
package/kernel/mac80211/patches/348-brcmfmac-Delete-unnecessary-variable-initialisation.patch [new file with mode: 0644]
package/kernel/mac80211/patches/349-0001-brcmfmac-clear-eventmask-array-before-using-it.patch [new file with mode: 0644]
package/kernel/mac80211/patches/349-0002-brcmfmac-fix-clearing-wowl-wake-indicators.patch [new file with mode: 0644]
package/kernel/mac80211/patches/349-0003-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch [new file with mode: 0644]
package/kernel/mac80211/patches/349-0004-brcmfmac-fix-p2p-scan-abort-null-pointer-exception.patch [new file with mode: 0644]
package/kernel/mac80211/patches/349-0005-brcmfmac-screening-firmware-event-packet.patch [new file with mode: 0644]
package/kernel/mac80211/patches/349-0006-brcmfmac-cleanup-ampdu-rx-host-reorder-code.patch [new file with mode: 0644]
package/kernel/mac80211/patches/349-0007-brcmfmac-revise-handling-events-in-receive-path.patch [new file with mode: 0644]
package/kernel/mac80211/patches/349-0008-brcmfmac-create-common-function-for-handling-brcmf_p.patch [new file with mode: 0644]
package/kernel/mac80211/patches/351-0005-brcmfmac-rework-function-picking-free-BSS-index.patch
package/kernel/mac80211/patches/351-0007-brcmutil-add-field-storing-control-channel-to-the-st.patch
package/kernel/mac80211/patches/351-0008-brcmfmac-support-get_channel-cfg80211-callback.patch
package/kernel/mac80211/patches/351-0010-brcmfmac-fix-setting-AP-channel-with-new-firmwares.patch
package/kernel/mac80211/patches/351-0011-brcmfmac-don-t-remove-interface-on-link-down-firmwar.patch
package/kernel/mac80211/patches/351-0017-brcmfmac-drop-unused-pm_block-vif-attribute.patch
package/kernel/mac80211/patches/351-0019-brcmfmac-slightly-simplify-building-interface-combin.patch
package/kernel/mac80211/patches/351-0020-brcmfmac-fix-lockup-when-removing-P2P-interface-afte.patch
package/kernel/mac80211/patches/351-0021-brcmfmac-use-const-char-for-interface-name-in-brcmf_.patch
package/kernel/mac80211/patches/351-0026-brcmfmac-respect-hidden_ssid-for-AP-interfaces.patch
package/kernel/mac80211/patches/351-0027-brcmfmac-restore-stopping-netdev-queue-when-bus-clog.patch
package/kernel/mac80211/patches/860-brcmfmac-add-missing-eth_type_trans-call.patch [new file with mode: 0644]
package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.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 (file)
index 0000000..39f4383
--- /dev/null
@@ -0,0 +1,54 @@
+From: Hui Wang <hui.wang@canonical.com>
+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 <brudley@broadcom.com>
+Cc: Hante Meuleman <meuleman@broadcom.com>
+Cc: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Cc: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Cc: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Hui Wang <hui.wang@canonical.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- 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/345-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch b/package/kernel/mac80211/patches/345-brcmfmac-insert-default-boardrev-in-nvram-data-if-mi.patch
deleted file mode 100644 (file)
index f293401..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-From: Hante Meuleman <hante.meuleman@broadcom.com>
-Date: Mon, 11 Apr 2016 11:35:23 +0200
-Subject: [PATCH] brcmfmac: insert default boardrev in nvram data if
- missing
-
-Some nvram files/stores come without the boardrev information,
-but firmware requires this to be set. When not found in nvram then
-add a default boardrev string to the nvram data.
-
-Reported-by: Rafal Milecki <zajec5@gmail.com>
-Reviewed-by: Arend Van Spriel <arend@broadcom.com>
-Reviewed-by: Franky (Zhenhui) Lin <franky.lin@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Signed-off-by: Hante Meuleman <hante.meuleman@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/firmware.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
-@@ -29,6 +29,7 @@
- #define BRCMF_FW_MAX_NVRAM_SIZE                       64000
- #define BRCMF_FW_NVRAM_DEVPATH_LEN            19      /* devpath0=pcie/1/4/ */
- #define BRCMF_FW_NVRAM_PCIEDEV_LEN            10      /* pcie/1/4/ + \0 */
-+#define BRCMF_FW_DEFAULT_BOARDREV             "boardrev=0xff"
- enum nvram_parser_state {
-       IDLE,
-@@ -51,6 +52,7 @@ enum nvram_parser_state {
-  * @entry: start position of key,value entry.
-  * @multi_dev_v1: detect pcie multi device v1 (compressed).
-  * @multi_dev_v2: detect pcie multi device v2.
-+ * @boardrev_found: nvram contains boardrev information.
-  */
- struct nvram_parser {
-       enum nvram_parser_state state;
-@@ -63,6 +65,7 @@ struct nvram_parser {
-       u32 entry;
-       bool multi_dev_v1;
-       bool multi_dev_v2;
-+      bool boardrev_found;
- };
- /**
-@@ -125,6 +128,8 @@ static enum nvram_parser_state brcmf_nvr
-                       nvp->multi_dev_v1 = true;
-               if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0)
-                       nvp->multi_dev_v2 = true;
-+              if (strncmp(&nvp->data[nvp->entry], "boardrev", 8) == 0)
-+                      nvp->boardrev_found = true;
-       } else if (!is_nvram_char(c) || c == ' ') {
-               brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
-                         nvp->line, nvp->column);
-@@ -284,6 +289,8 @@ static void brcmf_fw_strip_multi_v1(stru
-       while (i < nvp->nvram_len) {
-               if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) {
-                       i += 2;
-+                      if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
-+                              nvp->boardrev_found = true;
-                       while (nvp->nvram[i] != 0) {
-                               nvram[j] = nvp->nvram[i];
-                               i++;
-@@ -335,6 +342,8 @@ static void brcmf_fw_strip_multi_v2(stru
-       while (i < nvp->nvram_len - len) {
-               if (strncmp(&nvp->nvram[i], prefix, len) == 0) {
-                       i += len;
-+                      if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
-+                              nvp->boardrev_found = true;
-                       while (nvp->nvram[i] != 0) {
-                               nvram[j] = nvp->nvram[i];
-                               i++;
-@@ -356,6 +365,18 @@ fail:
-       nvp->nvram_len = 0;
- }
-+static void brcmf_fw_add_defaults(struct nvram_parser *nvp)
-+{
-+      if (nvp->boardrev_found)
-+              return;
-+
-+      memcpy(&nvp->nvram[nvp->nvram_len], &BRCMF_FW_DEFAULT_BOARDREV,
-+             strlen(BRCMF_FW_DEFAULT_BOARDREV));
-+      nvp->nvram_len += strlen(BRCMF_FW_DEFAULT_BOARDREV);
-+      nvp->nvram[nvp->nvram_len] = '\0';
-+      nvp->nvram_len++;
-+}
-+
- /* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
-  * and ending in a NUL. Removes carriage returns, empty lines, comment lines,
-  * and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
-@@ -377,16 +398,21 @@ static void *brcmf_fw_nvram_strip(const
-               if (nvp.state == END)
-                       break;
-       }
--      if (nvp.multi_dev_v1)
-+      if (nvp.multi_dev_v1) {
-+              nvp.boardrev_found = false;
-               brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr);
--      else if (nvp.multi_dev_v2)
-+      } else if (nvp.multi_dev_v2) {
-+              nvp.boardrev_found = false;
-               brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr);
-+      }
-       if (nvp.nvram_len == 0) {
-               kfree(nvp.nvram);
-               return NULL;
-       }
-+      brcmf_fw_add_defaults(&nvp);
-+
-       pad = nvp.nvram_len;
-       *new_length = roundup(nvp.nvram_len + 1, 4);
-       while (pad != *new_length) {
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 (file)
index 0000000..3c9ed42
--- /dev/null
@@ -0,0 +1,21 @@
+From: Dan Carpenter <dan.carpenter@oracle.com>
+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 <dan.carpenter@oracle.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- 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 (file)
index 0000000..d1deb6e
--- /dev/null
@@ -0,0 +1,24 @@
+From: Colin Ian King <colin.king@canonical.com>
+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 <colin.king@canonical.com>
+Reviewed-by: Julian Calaby <julian.calaby@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- 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 (file)
index 0000000..d399b26
--- /dev/null
@@ -0,0 +1,26 @@
+From: Markus Elfring <elfring@users.sourceforge.net>
+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 <elfring@users.sourceforge.net>
+Acked-by: Arend van Spriel <arend@broadcom.com>
+[Rewrote commit message]
+Signed-off-by: Julian Calaby <julian.calaby@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- 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 (file)
index 0000000..0acb4fa
--- /dev/null
@@ -0,0 +1,27 @@
+From: Hante Meuleman <hante.meuleman@broadcom.com>
+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 <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Signed-off-by: Hante Meuleman <hante.meuleman@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/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 (file)
index 0000000..8d30678
--- /dev/null
@@ -0,0 +1,27 @@
+From: Hante Meuleman <hante.meuleman@broadcom.com>
+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 <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Signed-off-by: Hante Meuleman <hante.meuleman@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/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/349-0003-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
new file mode 100644 (file)
index 0000000..f293401
--- /dev/null
@@ -0,0 +1,114 @@
+From: Hante Meuleman <hante.meuleman@broadcom.com>
+Date: Mon, 11 Apr 2016 11:35:23 +0200
+Subject: [PATCH] brcmfmac: insert default boardrev in nvram data if
+ missing
+
+Some nvram files/stores come without the boardrev information,
+but firmware requires this to be set. When not found in nvram then
+add a default boardrev string to the nvram data.
+
+Reported-by: Rafal Milecki <zajec5@gmail.com>
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <franky.lin@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Signed-off-by: Hante Meuleman <hante.meuleman@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/firmware.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+@@ -29,6 +29,7 @@
+ #define BRCMF_FW_MAX_NVRAM_SIZE                       64000
+ #define BRCMF_FW_NVRAM_DEVPATH_LEN            19      /* devpath0=pcie/1/4/ */
+ #define BRCMF_FW_NVRAM_PCIEDEV_LEN            10      /* pcie/1/4/ + \0 */
++#define BRCMF_FW_DEFAULT_BOARDREV             "boardrev=0xff"
+ enum nvram_parser_state {
+       IDLE,
+@@ -51,6 +52,7 @@ enum nvram_parser_state {
+  * @entry: start position of key,value entry.
+  * @multi_dev_v1: detect pcie multi device v1 (compressed).
+  * @multi_dev_v2: detect pcie multi device v2.
++ * @boardrev_found: nvram contains boardrev information.
+  */
+ struct nvram_parser {
+       enum nvram_parser_state state;
+@@ -63,6 +65,7 @@ struct nvram_parser {
+       u32 entry;
+       bool multi_dev_v1;
+       bool multi_dev_v2;
++      bool boardrev_found;
+ };
+ /**
+@@ -125,6 +128,8 @@ static enum nvram_parser_state brcmf_nvr
+                       nvp->multi_dev_v1 = true;
+               if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0)
+                       nvp->multi_dev_v2 = true;
++              if (strncmp(&nvp->data[nvp->entry], "boardrev", 8) == 0)
++                      nvp->boardrev_found = true;
+       } else if (!is_nvram_char(c) || c == ' ') {
+               brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
+                         nvp->line, nvp->column);
+@@ -284,6 +289,8 @@ static void brcmf_fw_strip_multi_v1(stru
+       while (i < nvp->nvram_len) {
+               if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) {
+                       i += 2;
++                      if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
++                              nvp->boardrev_found = true;
+                       while (nvp->nvram[i] != 0) {
+                               nvram[j] = nvp->nvram[i];
+                               i++;
+@@ -335,6 +342,8 @@ static void brcmf_fw_strip_multi_v2(stru
+       while (i < nvp->nvram_len - len) {
+               if (strncmp(&nvp->nvram[i], prefix, len) == 0) {
+                       i += len;
++                      if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
++                              nvp->boardrev_found = true;
+                       while (nvp->nvram[i] != 0) {
+                               nvram[j] = nvp->nvram[i];
+                               i++;
+@@ -356,6 +365,18 @@ fail:
+       nvp->nvram_len = 0;
+ }
++static void brcmf_fw_add_defaults(struct nvram_parser *nvp)
++{
++      if (nvp->boardrev_found)
++              return;
++
++      memcpy(&nvp->nvram[nvp->nvram_len], &BRCMF_FW_DEFAULT_BOARDREV,
++             strlen(BRCMF_FW_DEFAULT_BOARDREV));
++      nvp->nvram_len += strlen(BRCMF_FW_DEFAULT_BOARDREV);
++      nvp->nvram[nvp->nvram_len] = '\0';
++      nvp->nvram_len++;
++}
++
+ /* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
+  * and ending in a NUL. Removes carriage returns, empty lines, comment lines,
+  * and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
+@@ -377,16 +398,21 @@ static void *brcmf_fw_nvram_strip(const
+               if (nvp.state == END)
+                       break;
+       }
+-      if (nvp.multi_dev_v1)
++      if (nvp.multi_dev_v1) {
++              nvp.boardrev_found = false;
+               brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr);
+-      else if (nvp.multi_dev_v2)
++      } else if (nvp.multi_dev_v2) {
++              nvp.boardrev_found = false;
+               brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr);
++      }
+       if (nvp.nvram_len == 0) {
+               kfree(nvp.nvram);
+               return NULL;
+       }
++      brcmf_fw_add_defaults(&nvp);
++
+       pad = nvp.nvram_len;
+       *new_length = roundup(nvp.nvram_len + 1, 4);
+       while (pad != *new_length) {
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 (file)
index 0000000..ed0c83f
--- /dev/null
@@ -0,0 +1,29 @@
+From: Hante Meuleman <hante.meuleman@broadcom.com>
+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 <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Signed-off-by: Hante Meuleman <hante.meuleman@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/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 (file)
index 0000000..4d26404
--- /dev/null
@@ -0,0 +1,297 @@
+From: Franky Lin <franky.lin@broadcom.com>
+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 <pieter-paul.giesberts@broadcom.com>
+Signed-off-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/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 <linux/types.h>
+ #include <linux/netdevice.h>
++#include <linux/etherdevice.h>
+ #include <brcmu_utils.h>
+ #include <brcmu_wifi.h>
+@@ -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 (file)
index 0000000..33b263d
--- /dev/null
@@ -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 */
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 (file)
index 0000000..a43feff
--- /dev/null
@@ -0,0 +1,139 @@
+From: Arend van Spriel <arend@broadcom.com>
+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 <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/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 (file)
index 0000000..08ea235
--- /dev/null
@@ -0,0 +1,88 @@
+From: Arend van Spriel <arend@broadcom.com>
+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 <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/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);
index f2427487234cb75c9bd0d6bfa3172fd37d9c3b82..c602f2272a4a322d9e5246c517eecfc3a00e1db2 100644 (file)
@@ -76,7 +76,7 @@ Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
  
 --- 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 <kvalo@codeaurora.org>
  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);
index 6f064d16efc8cd83435930ca3612867313d86d36..a79c9a2e93732d8c4c15af55387e378afd72001a 100644 (file)
@@ -54,7 +54,7 @@ Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
        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 <kvalo@codeaurora.org>
        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 <kvalo@codeaurora.org>
  
                /* 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++) {
index 3e16c4bfc7c2878e342c2c898e8e8930ba399811..2c536d178d6746aca311d6ce16421a609061a3ad 100644 (file)
@@ -15,7 +15,7 @@ Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 
 --- 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 <kvalo@codeaurora.org>
  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,
index bf06a767d4d08b4fb0e4eb9fb23eef951e5ab585..a2e18a5fe994ed40619f5f12e936765ffeec2314 100644 (file)
@@ -32,7 +32,7 @@ Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 
 --- 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 <kvalo@codeaurora.org>
        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 <kvalo@codeaurora.org>
                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 <kvalo@codeaurora.org>
        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 <kvalo@codeaurora.org>
                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 <kvalo@codeaurora.org>
                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");
index 6ef145338ce3e9d86f4b1b7b9e694e7dcfeee319..167e4347d5ff00cf87cf352058723bd58e1468ce 100644 (file)
@@ -41,7 +41,7 @@ Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 
 --- 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 <kvalo@codeaurora.org>
        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);
index f5bacd22db37401047e4b16e1ad57831f58a5f05..3b407db355626c2f743bf28b8f9b2b259885136c 100644 (file)
@@ -24,7 +24,7 @@ Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
        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 <kvalo@codeaurora.org>
  {
        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 <kvalo@codeaurora.org>
        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);
  
index 7d57f72da2fe3062c8d319cda335e32a85a0e1d2..1b885e0b89f087ce88b707b7213511ca87157955 100644 (file)
@@ -23,7 +23,7 @@ Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 
 --- 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 <kvalo@codeaurora.org>
        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 <kvalo@codeaurora.org>
        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 <kvalo@codeaurora.org>
                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 <kvalo@codeaurora.org>
                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++;
index 995688a6b8c60c201e04496d0f3ec9718979197a..0dd88bc7a6fdf970de2255b5b6e8179161e10705 100644 (file)
@@ -29,7 +29,7 @@ Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 
 --- 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 <kvalo@codeaurora.org>
  }
  
  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 <kvalo@codeaurora.org>
                        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 <kvalo@codeaurora.org>
  {
        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 <kvalo@codeaurora.org>
        } 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 <kvalo@codeaurora.org>
  }
  
  #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 <kvalo@codeaurora.org>
        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 <kvalo@codeaurora.org>
  
 --- 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);
index 21ff7d54e08826766263f3a55502bc14a0dae1bc..24f06c41296ee3ff037fb92dd2792d964dba2a18 100644 (file)
@@ -17,7 +17,7 @@ Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 
 --- 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 <kvalo@codeaurora.org>
        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,
index 9d64691da7419a906019675611bde43f2dec9c6b..94ab246413f31c1fa986c94788a377d3dd810e04 100644 (file)
@@ -14,7 +14,7 @@ Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 
 --- 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 <kvalo@codeaurora.org>
                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;
                }
  
index 0fac3a697d607e6ba791a85628ec7913bfa60765..d360b27f46a33f17e9bc09a3d107d5cd99c69a09 100644 (file)
@@ -23,7 +23,7 @@ Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 
 --- 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 (file)
index 0000000..46227c4
--- /dev/null
@@ -0,0 +1,26 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+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 <zajec5@gmail.com>
+---
+
+--- 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);
+ }
index 9850e2dad34eaac0fc9d571c849f63580afad827..ae571c99ab151245355d0080a6475bcabbb9a2fb 100644 (file)
@@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
 
 --- 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;