Преглед изворни кода

mac80211: backport latest patches except for NVRAM support

We sill don't use kernel 4.2 which is required for backporting using
upstream NVRAM support patch.

Signed-off-by: Rafał Miłecki <[email protected]>

SVN-Revision: 46724
Rafał Miłecki пре 10 година
родитељ
комит
7a68c31a81

+ 45 - 0
package/kernel/mac80211/patches/311-brcmfmac-dhd_sdio.c-use-existing-atomic_or-primitive.patch

@@ -0,0 +1,45 @@
+From: Vineet Gupta <[email protected]>
+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 <[email protected]>
+---
+
+--- 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);
+ 

+ 46 - 0
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?= <[email protected]>
+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 <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+
+--- 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);

+ 204 - 0
package/kernel/mac80211/patches/313-brcmfmac-correct-interface-combination-info.patch

@@ -0,0 +1,204 @@
+From: Arend van Spriel <[email protected]>
+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 <[email protected]>
+Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
+Reviewed-by: Pieter-Paul Giesberts <[email protected]>
+Reviewed-by: Pontus Fuchs <[email protected]>
+Signed-off-by: Arend van Spriel <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+
+--- 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);

+ 87 - 0
package/kernel/mac80211/patches/314-brcmfmac-add-debugfs-entry-for-msgbuf-statistics.patch

@@ -0,0 +1,87 @@
+From: Franky Lin <[email protected]>
+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 <[email protected]>
+Reviewed-by: Hante Meuleman <[email protected]>
+Reviewed-by: Pieter-Paul Giesberts <[email protected]>
+Signed-off-by: Franky Lin <[email protected]>
+Signed-off-by: Arend van Spriel <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+
+--- 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:

+ 83 - 0
package/kernel/mac80211/patches/315-brcmfmac-make-use-of-cfg80211_check_combinations.patch

@@ -0,0 +1,83 @@
+From: Arend van Spriel <[email protected]>
+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 <[email protected]>
+Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
+Reviewed-by: Pieter-Paul Giesberts <[email protected]>
+Signed-off-by: Arend van Spriel <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+
+--- 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:

+ 48 - 0
package/kernel/mac80211/patches/316-brcmfmac-block-the-correct-flowring-when-backup-queu.patch

@@ -0,0 +1,48 @@
+From: Franky Lin <[email protected]>
+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 <[email protected]>
+Reviewed-by: Hante Meuleman <[email protected]>
+Signed-off-by: Franky Lin <[email protected]>
+Signed-off-by: Arend van Spriel <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+
+--- 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;
+ 	}

+ 52 - 0
package/kernel/mac80211/patches/317-brcmfmac-bump-highest-event-number-for-4339-firmware.patch

@@ -0,0 +1,52 @@
+From: Arend van Spriel <[email protected]>
+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 <[email protected]>
+Reviewed-by: Hante Meuleman <[email protected]>
+Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
+Reviewed-by: Pieter-Paul Giesberts <[email protected]>
+Reviewed-by: Pontus Fuchs <[email protected]>
+Signed-off-by: Arend van Spriel <[email protected]>
+Signed-off-by: Kalle Valo <[email protected]>
+---
+
+--- 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
+ 

+ 4 - 3
package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch

@@ -10,12 +10,13 @@ Signed-off-by: Rafał Miłecki <[email protected]>
 
 --- 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 <[email protected]>
 +	}
 +
  	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) {