aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--package/kernel/mac80211/patches/311-brcmfmac-dhd_sdio.c-use-existing-atomic_or-primitive.patch45
-rw-r--r--package/kernel/mac80211/patches/312-brcmfmac-check-all-combinations-when-setting-wiphy-s.patch46
-rw-r--r--package/kernel/mac80211/patches/313-brcmfmac-correct-interface-combination-info.patch204
-rw-r--r--package/kernel/mac80211/patches/314-brcmfmac-add-debugfs-entry-for-msgbuf-statistics.patch87
-rw-r--r--package/kernel/mac80211/patches/315-brcmfmac-make-use-of-cfg80211_check_combinations.patch83
-rw-r--r--package/kernel/mac80211/patches/316-brcmfmac-block-the-correct-flowring-when-backup-queu.patch48
-rw-r--r--package/kernel/mac80211/patches/317-brcmfmac-bump-highest-event-number-for-4339-firmware.patch52
-rw-r--r--package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch7
8 files changed, 569 insertions, 3 deletions
diff --git a/package/kernel/mac80211/patches/311-brcmfmac-dhd_sdio.c-use-existing-atomic_or-primitive.patch b/package/kernel/mac80211/patches/311-brcmfmac-dhd_sdio.c-use-existing-atomic_or-primitive.patch
new file mode 100644
index 0000000000..e44f121ea3
--- /dev/null
+++ b/package/kernel/mac80211/patches/311-brcmfmac-dhd_sdio.c-use-existing-atomic_or-primitive.patch
@@ -0,0 +1,45 @@
+From: Vineet Gupta <Vineet.Gupta1@synopsys.com>
+Date: Thu, 9 Jul 2015 13:43:18 +0530
+Subject: [PATCH] brcmfmac: dhd_sdio.c: use existing atomic_or primitive
+
+There's already a generic implementation so use that instead.
+
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+@@ -2564,15 +2564,6 @@ static inline void brcmf_sdio_clrintr(st
+ }
+ }
+
+-static void atomic_orr(int val, atomic_t *v)
+-{
+- int old_val;
+-
+- old_val = atomic_read(v);
+- while (atomic_cmpxchg(v, old_val, val | old_val) != old_val)
+- old_val = atomic_read(v);
+-}
+-
+ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
+ {
+ struct brcmf_core *buscore;
+@@ -2595,7 +2586,7 @@ static int brcmf_sdio_intr_rstatus(struc
+ if (val) {
+ brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
+ bus->sdcnt.f1regdata++;
+- atomic_orr(val, &bus->intstatus);
++ atomic_or(val, &bus->intstatus);
+ }
+
+ return ret;
+@@ -2712,7 +2703,7 @@ static void brcmf_sdio_dpc(struct brcmf_
+
+ /* Keep still-pending events for next scheduling */
+ if (intstatus)
+- atomic_orr(intstatus, &bus->intstatus);
++ atomic_or(intstatus, &bus->intstatus);
+
+ brcmf_sdio_clrintr(bus);
+
diff --git a/package/kernel/mac80211/patches/312-brcmfmac-check-all-combinations-when-setting-wiphy-s.patch b/package/kernel/mac80211/patches/312-brcmfmac-check-all-combinations-when-setting-wiphy-s.patch
new file mode 100644
index 0000000000..bb27115d19
--- /dev/null
+++ b/package/kernel/mac80211/patches/312-brcmfmac-check-all-combinations-when-setting-wiphy-s.patch
@@ -0,0 +1,46 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Thu, 20 Aug 2015 00:16:42 +0200
+Subject: [PATCH] brcmfmac: check all combinations when setting wiphy's
+ addresses
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Broadcom is working on better reflection of interface combinations. With
+upcoming patches we may have 1st combination supporting less interfaces
+than others.
+To don't run out of addresses check all combinations to find the one
+with the greatest max_interfaces value.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -5786,7 +5786,9 @@ static void brcmf_wiphy_wowl_params(stru
+ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
+ {
+ struct brcmf_pub *drvr = ifp->drvr;
++ const struct ieee80211_iface_combination *combo;
+ struct ieee80211_supported_band *band;
++ u16 max_interfaces = 0;
+ __le32 bandlist[3];
+ u32 n_bands;
+ int err, i;
+@@ -5799,8 +5801,13 @@ static int brcmf_setup_wiphy(struct wiph
+ if (err)
+ return err;
+
+- for (i = 0; i < wiphy->iface_combinations->max_interfaces &&
+- i < ARRAY_SIZE(drvr->addresses); i++) {
++ for (i = 0, combo = wiphy->iface_combinations;
++ i < wiphy->n_iface_combinations; i++, combo++) {
++ max_interfaces = max(max_interfaces, combo->max_interfaces);
++ }
++
++ for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses);
++ i++) {
+ u8 *addr = drvr->addresses[i].addr;
+
+ memcpy(addr, drvr->mac, ETH_ALEN);
diff --git a/package/kernel/mac80211/patches/313-brcmfmac-correct-interface-combination-info.patch b/package/kernel/mac80211/patches/313-brcmfmac-correct-interface-combination-info.patch
new file mode 100644
index 0000000000..baee295cd5
--- /dev/null
+++ b/package/kernel/mac80211/patches/313-brcmfmac-correct-interface-combination-info.patch
@@ -0,0 +1,204 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 20 Aug 2015 22:06:03 +0200
+Subject: [PATCH] brcmfmac: correct interface combination info
+
+The interface combination provided by brcmfmac did not truly reflect
+the combinations supported by driver and/or firmware.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Pontus Fuchs <pontusf@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -5695,63 +5695,132 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
+ }
+ };
+
++/**
++ * brcmf_setup_ifmodes() - determine interface modes and combinations.
++ *
++ * @wiphy: wiphy object.
++ * @ifp: interface object needed for feat module api.
++ *
++ * The interface modes and combinations are determined dynamically here
++ * based on firmware functionality.
++ *
++ * no p2p and no mbss:
++ *
++ * #STA <= 1, #AP <= 1, channels = 1, 2 total
++ *
++ * no p2p and mbss:
++ *
++ * #STA <= 1, #AP <= 1, channels = 1, 2 total
++ * #AP <= 4, matching BI, channels = 1, 4 total
++ *
++ * p2p, no mchan, and mbss:
++ *
++ * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
++ * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
++ * #AP <= 4, matching BI, channels = 1, 4 total
++ *
++ * p2p, mchan, and mbss:
++ *
++ * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
++ * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
++ * #AP <= 4, matching BI, channels = 1, 4 total
++ */
+ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
+ {
+ struct ieee80211_iface_combination *combo = NULL;
+- struct ieee80211_iface_limit *limits = NULL;
+- int i = 0, max_iface_cnt;
++ struct ieee80211_iface_limit *c0_limits = NULL;
++ struct ieee80211_iface_limit *p2p_limits = NULL;
++ struct ieee80211_iface_limit *mbss_limits = NULL;
++ bool mbss, p2p;
++ int i, c, n_combos;
+
+- combo = kzalloc(sizeof(*combo), GFP_KERNEL);
++ mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
++ p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
++
++ n_combos = 1 + !!p2p + !!mbss;
++ combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
+ if (!combo)
+ goto err;
+
+- limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL);
+- if (!limits)
++ c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
++ if (!c0_limits)
+ goto err;
+
++ if (p2p) {
++ p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
++ if (!p2p_limits)
++ goto err;
++ }
++
++ if (mbss) {
++ mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
++ if (!mbss_limits)
++ goto err;
++ }
++
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP);
+
+- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
+- combo->num_different_channels = 2;
+- else
+- combo->num_different_channels = 1;
+-
+- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
+- limits[i].max = 1;
+- limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+- limits[i].max = 4;
+- limits[i++].types = BIT(NL80211_IFTYPE_AP);
+- max_iface_cnt = 5;
+- } else {
+- limits[i].max = 2;
+- limits[i++].types = BIT(NL80211_IFTYPE_STATION) |
+- BIT(NL80211_IFTYPE_AP);
+- max_iface_cnt = 2;
+- }
+-
+- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) {
++ c = 0;
++ i = 0;
++ combo[c].num_different_channels = 1;
++ c0_limits[i].max = 1;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++ if (p2p) {
++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
++ combo[c].num_different_channels = 2;
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
+- limits[i].max = 1;
+- limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+- BIT(NL80211_IFTYPE_P2P_GO);
+- limits[i].max = 1;
+- limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
+- max_iface_cnt += 2;
+- }
+- combo->max_interfaces = max_iface_cnt;
+- combo->limits = limits;
+- combo->n_limits = i;
++ c0_limits[i].max = 1;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
++ c0_limits[i].max = 1;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
++ BIT(NL80211_IFTYPE_P2P_GO);
++ } else {
++ c0_limits[i].max = 1;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
++ }
++ combo[c].max_interfaces = i;
++ combo[c].n_limits = i;
++ combo[c].limits = c0_limits;
++
++ if (p2p) {
++ c++;
++ i = 0;
++ combo[c].num_different_channels = 1;
++ p2p_limits[i].max = 1;
++ p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++ p2p_limits[i].max = 1;
++ p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
++ p2p_limits[i].max = 1;
++ p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
++ p2p_limits[i].max = 1;
++ p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
++ combo[c].max_interfaces = i;
++ combo[c].n_limits = i;
++ combo[c].limits = p2p_limits;
++ }
+
++ if (mbss) {
++ c++;
++ combo[c].beacon_int_infra_match = true;
++ combo[c].num_different_channels = 1;
++ mbss_limits[0].max = 4;
++ mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
++ combo[c].max_interfaces = 4;
++ combo[c].n_limits = 1;
++ combo[c].limits = mbss_limits;
++ }
++ wiphy->n_iface_combinations = n_combos;
+ wiphy->iface_combinations = combo;
+- wiphy->n_iface_combinations = 1;
+ return 0;
+
+ err:
+- kfree(limits);
++ kfree(c0_limits);
++ kfree(p2p_limits);
++ kfree(mbss_limits);
+ kfree(combo);
+ return -ENOMEM;
+ }
+@@ -6080,11 +6149,15 @@ static void brcmf_cfg80211_reg_notifier(
+
+ static void brcmf_free_wiphy(struct wiphy *wiphy)
+ {
++ int i;
++
+ if (!wiphy)
+ return;
+
+- if (wiphy->iface_combinations)
+- kfree(wiphy->iface_combinations->limits);
++ if (wiphy->iface_combinations) {
++ for (i = 0; i < wiphy->n_iface_combinations; i++)
++ kfree(wiphy->iface_combinations[i].limits);
++ }
+ kfree(wiphy->iface_combinations);
+ if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
+ kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
diff --git a/package/kernel/mac80211/patches/314-brcmfmac-add-debugfs-entry-for-msgbuf-statistics.patch b/package/kernel/mac80211/patches/314-brcmfmac-add-debugfs-entry-for-msgbuf-statistics.patch
new file mode 100644
index 0000000000..9768ef2771
--- /dev/null
+++ b/package/kernel/mac80211/patches/314-brcmfmac-add-debugfs-entry-for-msgbuf-statistics.patch
@@ -0,0 +1,87 @@
+From: Franky Lin <frankyl@broadcom.com>
+Date: Thu, 20 Aug 2015 22:06:04 +0200
+Subject: [PATCH] brcmfmac: add debugfs entry for msgbuf statistics
+
+Expose ring buffer read/write pointers and other useful statistics
+through debugfs.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Franky Lin <frankyl@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+@@ -1360,6 +1360,60 @@ void brcmf_msgbuf_delete_flowring(struct
+ }
+ }
+
++#ifdef DEBUG
++static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)
++{
++ struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
++ struct brcmf_pub *drvr = bus_if->drvr;
++ struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
++ struct brcmf_commonring *commonring;
++ u16 i;
++ struct brcmf_flowring_ring *ring;
++ struct brcmf_flowring_hash *hash;
++
++ commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];
++ seq_printf(seq, "h2d_ctl_submit: rp %4u, wp %4u, depth %4u\n",
++ commonring->r_ptr, commonring->w_ptr, commonring->depth);
++ commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT];
++ seq_printf(seq, "h2d_rx_submit: rp %4u, wp %4u, depth %4u\n",
++ commonring->r_ptr, commonring->w_ptr, commonring->depth);
++ commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE];
++ seq_printf(seq, "d2h_ctl_cmplt: rp %4u, wp %4u, depth %4u\n",
++ commonring->r_ptr, commonring->w_ptr, commonring->depth);
++ commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE];
++ seq_printf(seq, "d2h_tx_cmplt: rp %4u, wp %4u, depth %4u\n",
++ commonring->r_ptr, commonring->w_ptr, commonring->depth);
++ commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE];
++ seq_printf(seq, "d2h_rx_cmplt: rp %4u, wp %4u, depth %4u\n",
++ commonring->r_ptr, commonring->w_ptr, commonring->depth);
++
++ seq_printf(seq, "\nh2d_flowrings: depth %u\n",
++ BRCMF_H2D_TXFLOWRING_MAX_ITEM);
++ seq_puts(seq, "Active flowrings:\n");
++ hash = msgbuf->flow->hash;
++ for (i = 0; i < msgbuf->flow->nrofrings; i++) {
++ if (!msgbuf->flow->rings[i])
++ continue;
++ ring = msgbuf->flow->rings[i];
++ if (ring->status != RING_OPEN)
++ continue;
++ commonring = msgbuf->flowrings[i];
++ hash = &msgbuf->flow->hash[ring->hash_id];
++ seq_printf(seq, "id %3u: rp %4u, wp %4u, qlen %4u, blocked %u\n"
++ " ifidx %u, fifo %u, da %pM\n",
++ i, commonring->r_ptr, commonring->w_ptr,
++ skb_queue_len(&ring->skblist), ring->blocked,
++ hash->ifidx, hash->fifo, hash->mac);
++ }
++
++ return 0;
++}
++#else
++static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)
++{
++ return 0;
++}
++#endif
+
+ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
+ {
+@@ -1460,6 +1514,8 @@ int brcmf_proto_msgbuf_attach(struct brc
+ spin_lock_init(&msgbuf->flowring_work_lock);
+ INIT_LIST_HEAD(&msgbuf->work_queue);
+
++ brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read);
++
+ return 0;
+
+ fail:
diff --git a/package/kernel/mac80211/patches/315-brcmfmac-make-use-of-cfg80211_check_combinations.patch b/package/kernel/mac80211/patches/315-brcmfmac-make-use-of-cfg80211_check_combinations.patch
new file mode 100644
index 0000000000..281f02b7dc
--- /dev/null
+++ b/package/kernel/mac80211/patches/315-brcmfmac-make-use-of-cfg80211_check_combinations.patch
@@ -0,0 +1,83 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 20 Aug 2015 22:06:05 +0200
+Subject: [PATCH] brcmfmac: make use of cfg80211_check_combinations()
+
+Use cfg80211_check_combinations() so we can bail out early when an
+interface add or change results in an invalid combination.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -469,6 +469,36 @@ brcmf_find_wpsie(const u8 *parse, u32 le
+ return NULL;
+ }
+
++static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
++ struct brcmf_cfg80211_vif *vif,
++ enum nl80211_iftype new_type)
++{
++ int iftype_num[NUM_NL80211_IFTYPES];
++ struct brcmf_cfg80211_vif *pos;
++
++ memset(&iftype_num[0], 0, sizeof(iftype_num));
++ list_for_each_entry(pos, &cfg->vif_list, list)
++ if (pos == vif)
++ iftype_num[new_type]++;
++ else
++ iftype_num[pos->wdev.iftype]++;
++
++ return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
++}
++
++static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
++ enum nl80211_iftype new_type)
++{
++ int iftype_num[NUM_NL80211_IFTYPES];
++ struct brcmf_cfg80211_vif *pos;
++
++ memset(&iftype_num[0], 0, sizeof(iftype_num));
++ list_for_each_entry(pos, &cfg->vif_list, list)
++ iftype_num[pos->wdev.iftype]++;
++
++ iftype_num[new_type]++;
++ return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
++}
+
+ static void convert_key_from_CPU(struct brcmf_wsec_key *key,
+ struct brcmf_wsec_key_le *key_le)
+@@ -663,8 +693,14 @@ static struct wireless_dev *brcmf_cfg802
+ struct vif_params *params)
+ {
+ struct wireless_dev *wdev;
++ int err;
+
+ brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
++ err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
++ if (err) {
++ brcmf_err("iface validation failed: err=%d\n", err);
++ return ERR_PTR(err);
++ }
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+@@ -823,8 +859,12 @@ brcmf_cfg80211_change_iface(struct wiphy
+ s32 ap = 0;
+ s32 err = 0;
+
+- brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
+-
++ brcmf_dbg(TRACE, "Enter, idx=%d, type=%d\n", ifp->bssidx, type);
++ err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
++ if (err) {
++ brcmf_err("iface validation failed: err=%d\n", err);
++ return err;
++ }
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_WDS:
diff --git a/package/kernel/mac80211/patches/316-brcmfmac-block-the-correct-flowring-when-backup-queu.patch b/package/kernel/mac80211/patches/316-brcmfmac-block-the-correct-flowring-when-backup-queu.patch
new file mode 100644
index 0000000000..2d5f7b9be7
--- /dev/null
+++ b/package/kernel/mac80211/patches/316-brcmfmac-block-the-correct-flowring-when-backup-queu.patch
@@ -0,0 +1,48 @@
+From: Franky Lin <frankyl@broadcom.com>
+Date: Thu, 20 Aug 2015 22:06:06 +0200
+Subject: [PATCH] brcmfmac: block the correct flowring when backup queue
+ overflow
+
+brcmf_flowring_block blocks the last active flowring under the same
+interface instead of the one provided by caller. This could lead to a
+dead lock of netif stop if there are more than one flowring under the
+interface and the traffic is high enough so brcmf_flowring_enqueue can
+not unblock the ring right away.
+
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Franky Lin <frankyl@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
+@@ -194,11 +194,15 @@ static void brcmf_flowring_block(struct
+ spin_lock_irqsave(&flow->block_lock, flags);
+
+ ring = flow->rings[flowid];
++ if (ring->blocked == blocked) {
++ spin_unlock_irqrestore(&flow->block_lock, flags);
++ return;
++ }
+ ifidx = brcmf_flowring_ifidx_get(flow, flowid);
+
+ currently_blocked = false;
+ for (i = 0; i < flow->nrofrings; i++) {
+- if (flow->rings[i]) {
++ if ((flow->rings[i]) && (i != flowid)) {
+ ring = flow->rings[i];
+ if ((ring->status == RING_OPEN) &&
+ (brcmf_flowring_ifidx_get(flow, i) == ifidx)) {
+@@ -209,8 +213,8 @@ static void brcmf_flowring_block(struct
+ }
+ }
+ }
+- ring->blocked = blocked;
+- if (currently_blocked == blocked) {
++ flow->rings[flowid]->blocked = blocked;
++ if (currently_blocked) {
+ spin_unlock_irqrestore(&flow->block_lock, flags);
+ return;
+ }
diff --git a/package/kernel/mac80211/patches/317-brcmfmac-bump-highest-event-number-for-4339-firmware.patch b/package/kernel/mac80211/patches/317-brcmfmac-bump-highest-event-number-for-4339-firmware.patch
new file mode 100644
index 0000000000..7378401c52
--- /dev/null
+++ b/package/kernel/mac80211/patches/317-brcmfmac-bump-highest-event-number-for-4339-firmware.patch
@@ -0,0 +1,52 @@
+From: Arend van Spriel <arend@broadcom.com>
+Date: Thu, 20 Aug 2015 22:06:07 +0200
+Subject: [PATCH] brcmfmac: bump highest event number for 4339 firmware
+
+The event mask length is determined by the highest event number
+that is specified in the driver. When this length is shorter than
+firmware expects setting event mask will fail and device becomes
+pretty useless. This issue was reported with bcm4339 firmware that
+was recently released.
+
+Reported-by: Pontus Fuchs <pontusf@broadcom.com>
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Pontus Fuchs <pontusf@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
+@@ -85,7 +85,6 @@ struct brcmf_event;
+ BRCMF_ENUM_DEF(IF, 54) \
+ BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \
+ BRCMF_ENUM_DEF(RSSI, 56) \
+- BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \
+ BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \
+ BRCMF_ENUM_DEF(ACTION_FRAME, 59) \
+ BRCMF_ENUM_DEF(ACTION_FRAME_COMPLETE, 60) \
+@@ -103,8 +102,7 @@ struct brcmf_event;
+ BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
+ BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \
+ BRCMF_ENUM_DEF(TDLS_PEER_EVENT, 92) \
+- BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \
+- BRCMF_ENUM_DEF(PSTA_PRIMARY_INTF_IND, 128)
++ BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127)
+
+ #define BRCMF_ENUM_DEF(id, val) \
+ BRCMF_E_##id = (val),
+@@ -112,7 +110,11 @@ struct brcmf_event;
+ /* firmware event codes sent by the dongle */
+ enum brcmf_fweh_event_code {
+ BRCMF_FWEH_EVENT_ENUM_DEFLIST
+- BRCMF_E_LAST
++ /* this determines event mask length which must match
++ * minimum length check in device firmware so it is
++ * hard-coded here.
++ */
++ BRCMF_E_LAST = 139
+ };
+ #undef BRCMF_ENUM_DEF
+
diff --git a/package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch b/package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch
index 49b223d724..5fdfa37277 100644
--- a/package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch
+++ b/package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch
@@ -10,12 +10,13 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-@@ -662,8 +662,36 @@ static struct wireless_dev *brcmf_cfg802
+@@ -692,9 +692,37 @@ static struct wireless_dev *brcmf_cfg802
u32 *flags,
struct vif_params *params)
{
+ struct net_device *dev;
struct wireless_dev *wdev;
+ int err;
+ /*
+ * There is a bug with in-firmware BSS management. When adding virtual
@@ -45,5 +46,5 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+ }
+
brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
- switch (type) {
- case NL80211_IFTYPE_ADHOC:
+ err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type);
+ if (err) {