mac80211: update brcmfmac to the latest version

This also adds one patchset of pending changes that fix support for
multiple interfaces. It was somehow broken.
Driver couldn't correctly match firmware and system interfaces resulting
in not working APs and WARNINGs.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>

git-svn-id: svn://svn.openwrt.org/openwrt/branches/chaos_calmer@46736 3c298f89-4303-0410-b956-a3cf2f4a3e73
master
Rafał Miłecki 2015-08-26 22:57:54 +00:00
parent e32144bf9d
commit ae82d6b9e6
27 changed files with 2281 additions and 12 deletions

View File

@ -0,0 +1,44 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Thu, 11 Jun 2015 00:12:21 +0200
Subject: [PATCH] brcmfmac: free ifp for non-netdev interface in p2p module
Making it more clear by freeing the ifp in same place where the
vif object is freed.
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/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -867,8 +867,6 @@ static void brcmf_del_if(struct brcmf_pu
}
/* unregister will take care of freeing it */
unregister_netdev(ifp->ndev);
- } else {
- kfree(ifp);
}
}
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -2238,6 +2238,7 @@ static void brcmf_p2p_delete_p2pdev(stru
{
cfg80211_unregister_wdev(&vif->wdev);
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+ kfree(vif->ifp);
brcmf_free_vif(vif);
}
@@ -2361,6 +2362,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
break;
case NL80211_IFTYPE_P2P_DEVICE:
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+ brcmf_p2p_deinit_discovery(p2p);
brcmf_p2p_delete_p2pdev(p2p, vif);
return 0;
default:

View File

@ -0,0 +1,225 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Thu, 11 Jun 2015 00:12:22 +0200
Subject: [PATCH] brcmfmac: move p2p attach/detach functions
Moving two functions in p2p.c as is so next change will be
easier to review.
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/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -1908,105 +1908,6 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probere
/**
- * brcmf_p2p_attach() - attach for P2P.
- *
- * @cfg: driver private data for cfg80211 interface.
- */
-s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
-{
- struct brcmf_if *pri_ifp;
- struct brcmf_if *p2p_ifp;
- struct brcmf_cfg80211_vif *p2p_vif;
- struct brcmf_p2p_info *p2p;
- struct brcmf_pub *drvr;
- s32 bssidx;
- s32 err = 0;
-
- p2p = &cfg->p2p;
- p2p->cfg = cfg;
-
- drvr = cfg->pub;
-
- pri_ifp = drvr->iflist[0];
- p2p_ifp = drvr->iflist[1];
-
- p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
-
- if (p2p_ifp) {
- p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
- false);
- if (IS_ERR(p2p_vif)) {
- brcmf_err("could not create discovery vif\n");
- err = -ENOMEM;
- goto exit;
- }
-
- p2p_vif->ifp = p2p_ifp;
- p2p_ifp->vif = p2p_vif;
- p2p_vif->wdev.netdev = p2p_ifp->ndev;
- p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev;
- SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy));
-
- p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
-
- brcmf_p2p_generate_bss_mac(p2p, NULL);
- memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
- brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
-
- /* Initialize P2P Discovery in the firmware */
- err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
- if (err < 0) {
- brcmf_err("set p2p_disc error\n");
- brcmf_free_vif(p2p_vif);
- goto exit;
- }
- /* obtain bsscfg index for P2P discovery */
- err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
- if (err < 0) {
- brcmf_err("retrieving discover bsscfg index failed\n");
- brcmf_free_vif(p2p_vif);
- goto exit;
- }
- /* Verify that firmware uses same bssidx as driver !! */
- if (p2p_ifp->bssidx != bssidx) {
- brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
- bssidx, p2p_ifp->bssidx);
- brcmf_free_vif(p2p_vif);
- goto exit;
- }
-
- init_completion(&p2p->send_af_done);
- INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
- init_completion(&p2p->afx_hdl.act_frm_scan);
- init_completion(&p2p->wait_next_af);
- }
-exit:
- return err;
-}
-
-
-/**
- * brcmf_p2p_detach() - detach P2P.
- *
- * @p2p: P2P specific data.
- */
-void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
-{
- struct brcmf_cfg80211_vif *vif;
-
- vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
- if (vif != NULL) {
- brcmf_p2p_cancel_remain_on_channel(vif->ifp);
- brcmf_p2p_deinit_discovery(p2p);
- /* remove discovery interface */
- brcmf_free_vif(vif);
- p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
- }
- /* just set it all to zero */
- memset(p2p, 0, sizeof(*p2p));
-}
-
-/**
* brcmf_p2p_get_current_chanspec() - Get current operation channel.
*
* @p2p: P2P specific data.
@@ -2425,3 +2326,102 @@ void brcmf_p2p_stop_device(struct wiphy
clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
mutex_unlock(&cfg->usr_sync);
}
+
+/**
+ * brcmf_p2p_attach() - attach for P2P.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ */
+s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_if *pri_ifp;
+ struct brcmf_if *p2p_ifp;
+ struct brcmf_cfg80211_vif *p2p_vif;
+ struct brcmf_p2p_info *p2p;
+ struct brcmf_pub *drvr;
+ s32 bssidx;
+ s32 err = 0;
+
+ p2p = &cfg->p2p;
+ p2p->cfg = cfg;
+
+ drvr = cfg->pub;
+
+ pri_ifp = drvr->iflist[0];
+ p2p_ifp = drvr->iflist[1];
+
+ p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
+
+ if (p2p_ifp) {
+ p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
+ false);
+ if (IS_ERR(p2p_vif)) {
+ brcmf_err("could not create discovery vif\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ p2p_vif->ifp = p2p_ifp;
+ p2p_ifp->vif = p2p_vif;
+ p2p_vif->wdev.netdev = p2p_ifp->ndev;
+ p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev;
+ SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy));
+
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
+
+ brcmf_p2p_generate_bss_mac(p2p, NULL);
+ memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+ brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
+
+ /* Initialize P2P Discovery in the firmware */
+ err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
+ if (err < 0) {
+ brcmf_err("set p2p_disc error\n");
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+ /* obtain bsscfg index for P2P discovery */
+ err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
+ if (err < 0) {
+ brcmf_err("retrieving discover bsscfg index failed\n");
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+ /* Verify that firmware uses same bssidx as driver !! */
+ if (p2p_ifp->bssidx != bssidx) {
+ brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
+ bssidx, p2p_ifp->bssidx);
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+
+ init_completion(&p2p->send_af_done);
+ INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
+ init_completion(&p2p->afx_hdl.act_frm_scan);
+ init_completion(&p2p->wait_next_af);
+ }
+exit:
+ return err;
+}
+
+/**
+ * brcmf_p2p_detach() - detach P2P.
+ *
+ * @p2p: P2P specific data.
+ */
+void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
+{
+ struct brcmf_cfg80211_vif *vif;
+
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ if (vif != NULL) {
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+ brcmf_p2p_deinit_discovery(p2p);
+ /* remove discovery interface */
+ brcmf_free_vif(vif);
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+ }
+ /* just set it all to zero */
+ memset(p2p, 0, sizeof(*p2p));
+}
+

View File

@ -0,0 +1,63 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Thu, 11 Jun 2015 00:12:23 +0200
Subject: [PATCH] brcmfmac: assure p2pdev is unregistered upon driver
unload
When unloading the driver with a p2pdev interface it resulted in
a warning upon calling wiphy_unregister() and subsequently a crash
in the driver. This patch assures the p2pdev is unregistered calling
unregister_wdev() before doing the wiphy_unregister().
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
@@ -6206,10 +6206,8 @@ void brcmf_cfg80211_detach(struct brcmf_
if (!cfg)
return;
- WARN_ON(!list_empty(&cfg->vif_list));
- wiphy_unregister(cfg->wiphy);
brcmf_btcoex_detach(cfg);
- brcmf_p2p_detach(&cfg->p2p);
+ wiphy_unregister(cfg->wiphy);
wl_deinit_priv(cfg);
brcmf_free_wiphy(cfg->wiphy);
}
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -1098,6 +1098,7 @@ void brcmf_detach(struct device *dev)
/* stop firmware event handling */
brcmf_fweh_detach(drvr);
+ brcmf_p2p_detach(&drvr->config->p2p);
brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
#include <net/cfg80211.h>
#include <brcmu_wifi.h>
@@ -2418,8 +2419,9 @@ void brcmf_p2p_detach(struct brcmf_p2p_i
brcmf_p2p_cancel_remain_on_channel(vif->ifp);
brcmf_p2p_deinit_discovery(p2p);
/* remove discovery interface */
- brcmf_free_vif(vif);
- p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+ rtnl_lock();
+ brcmf_p2p_delete_p2pdev(p2p, vif);
+ rtnl_unlock();
}
/* just set it all to zero */
memset(p2p, 0, sizeof(*p2p));

View File

@ -0,0 +1,27 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Mon, 15 Jun 2015 22:48:38 +0200
Subject: [PATCH] brcmfmac: fix double free of p2pdev interface
When freeing the driver ifp pointer it should also be removed from
the driver interface list, which is what brcmf_remove_interface()
does. Otherwise, the ifp pointer will be freed twice triggering
a kernel oops.
Fixes: f37d69a4babc ("brcmfmac: free ifp for non-netdev interface in p2p module")
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Hante Meuleman <meuleman@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/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -2140,7 +2140,7 @@ static void brcmf_p2p_delete_p2pdev(stru
{
cfg80211_unregister_wdev(&vif->wdev);
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
- kfree(vif->ifp);
+ brcmf_remove_interface(vif->ifp->drvr, vif->ifp->bssidx);
brcmf_free_vif(vif);
}

View File

@ -0,0 +1,29 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Mon, 15 Jun 2015 22:48:39 +0200
Subject: [PATCH] brcmfmac: make brcmf_p2p_detach() call conditional
During verification of error handling in brcmf_cfg80211_attach() a
null pointer dereference occurred upon calling brcmf_p2p_detach()
from brcmf_detach(). This should only be called when the
brcmf_cfg80211_attach() has succeeded.
Fixes: f7a40873d2fa ("brcmfmac: assure p2pdev is unregistered upon driver unload")
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/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -1098,7 +1098,8 @@ void brcmf_detach(struct device *dev)
/* stop firmware event handling */
brcmf_fweh_detach(drvr);
- brcmf_p2p_detach(&drvr->config->p2p);
+ if (drvr->config)
+ brcmf_p2p_detach(&drvr->config->p2p);
brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);

View File

@ -1,9 +1,6 @@
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
Date: Thu, 9 Jul 2015 16:53:30 +0200
From: Rafa? Mi?ecki <zajec5@gmail.com>
Date: Thu, 9 Jul 2015 17:07:08 +0200
Subject: [PATCH] brcmfmac: set wiphy's addresses to provide valid MACs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Broadcom's firmware requires every BSS to use MAC address with unique
last few bits. The amount of bits may depend on a particular firmware,
@ -15,12 +12,13 @@ We don't want to simply set addr_mask as it would also disallow using
locally administrated bit. Instead let's build a list of addresses
manually enabling 0x2 bit for extra interfaces.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
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
@@ -5812,6 +5812,7 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
@@ -5784,6 +5784,7 @@ static void brcmf_wiphy_wowl_params(stru
static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
{
@ -28,7 +26,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
struct ieee80211_supported_band *band;
__le32 bandlist[3];
u32 n_bands;
@@ -5825,6 +5826,19 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
@@ -5797,6 +5798,19 @@ static int brcmf_setup_wiphy(struct wiph
if (err)
return err;

View File

@ -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);

View File

@ -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
@@ -5785,7 +5785,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;
@@ -5798,8 +5800,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);

View File

@ -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
@@ -5694,63 +5694,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;
}
@@ -6079,11 +6148,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);

View File

@ -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:

View File

@ -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)
@@ -662,8 +692,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:
@@ -822,8 +858,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:

View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1,138 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:14:53 +0200
Subject: [PATCH] brcmfmac: consolidate ifp lookup in driver core
In rx path the firmware provide an interface index which is used to
map to a struct brcmf_if instance. However, this involves some trick
that is done in two places. This is changed by having driver core
providing brcmf_get_ifp() function.
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>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
@@ -276,6 +276,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
struct sk_buff *pktbuf)
{
struct brcmf_proto_bcdc_header *h;
+ struct brcmf_if *ifp;
brcmf_dbg(BCDC, "Enter\n");
@@ -289,30 +290,21 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
trace_brcmf_bcdchdr(pktbuf->data);
h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
- *ifidx = BCDC_GET_IF_IDX(h);
- if (*ifidx >= BRCMF_MAX_IFS) {
- brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
+ ifp = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h));
+ if (IS_ERR_OR_NULL(ifp)) {
+ brcmf_dbg(INFO, "no matching ifp found\n");
return -EBADE;
}
- /* The ifidx is the idx to map to matching netdev/ifp. When receiving
- * events this is easy because it contains the bssidx which maps
- * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
- * bssidx 1 is used for p2p0 and no data can be received or
- * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
- */
- if (*ifidx)
- (*ifidx)++;
-
if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) !=
BCDC_PROTO_VER) {
brcmf_err("%s: non-BCDC packet received, flags 0x%x\n",
- brcmf_ifname(drvr, *ifidx), h->flags);
+ brcmf_ifname(drvr, ifp->ifidx), h->flags);
return -EBADE;
}
if (h->flags & BCDC_FLAG_SUM_GOOD) {
brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
- brcmf_ifname(drvr, *ifidx), h->flags);
+ brcmf_ifname(drvr, ifp->ifidx), h->flags);
pktbuf->ip_summed = CHECKSUM_UNNECESSARY;
}
@@ -320,12 +312,15 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
skb_pull(pktbuf, BCDC_HEADER_LEN);
if (do_fws)
- brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);
+ brcmf_fws_hdrpull(drvr, ifp->ifidx, h->data_offset << 2,
+ pktbuf);
else
skb_pull(pktbuf, h->data_offset << 2);
if (pktbuf->len == 0)
return -ENODATA;
+
+ *ifidx = ifp->ifidx;
return 0;
}
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -83,6 +83,25 @@ char *brcmf_ifname(struct brcmf_pub *drv
return "<if_none>";
}
+struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx)
+{
+ if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
+ brcmf_err("ifidx %d out of range\n", ifidx);
+ return ERR_PTR(-ERANGE);
+ }
+
+ /* The ifidx is the idx to map to matching netdev/ifp. When receiving
+ * events this is easy because it contains the bssidx which maps
+ * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
+ * bssidx 1 is used for p2p0 and no data can be received or
+ * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
+ */
+ if (ifidx)
+ ifidx++;
+
+ return drvr->iflist[ifidx];
+}
+
static void _brcmf_set_multicast_list(struct work_struct *work)
{
struct brcmf_if *ifp;
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
@@ -202,7 +202,7 @@ int brcmf_netdev_wait_pend8021x(struct b
/* Return pointer to interface name */
char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
-
+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 bssidx, s32 ifidx,
char *name, u8 *mac_addr);
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
@@ -1081,16 +1081,8 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf
{
struct brcmf_if *ifp;
- /* The ifidx is the idx to map to matching netdev/ifp. When receiving
- * events this is easy because it contains the bssidx which maps
- * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
- * bssidx 1 is used for p2p0 and no data can be received or
- * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
- */
- if (ifidx)
- (ifidx)++;
- ifp = msgbuf->drvr->iflist[ifidx];
- if (!ifp || !ifp->ndev) {
+ ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
+ if (IS_ERR_OR_NULL(ifp) || !ifp->ndev) {
brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
brcmu_pkt_buf_free_skb(skb);
return;

View File

@ -0,0 +1,222 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:14:54 +0200
Subject: [PATCH] brcmfmac: make brcmf_proto_hdrpull() return struct
brcmf_if instance
Avoid spreading the ifidx in the driver, but have it return the
struct brcmf_if instance.
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>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
@@ -272,11 +272,11 @@ brcmf_proto_bcdc_hdrpush(struct brcmf_pu
}
static int
-brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
- struct sk_buff *pktbuf)
+brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws,
+ struct sk_buff *pktbuf, struct brcmf_if **ifp)
{
struct brcmf_proto_bcdc_header *h;
- struct brcmf_if *ifp;
+ struct brcmf_if *tmp_if;
brcmf_dbg(BCDC, "Enter\n");
@@ -290,21 +290,21 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
trace_brcmf_bcdchdr(pktbuf->data);
h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
- ifp = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h));
- if (IS_ERR_OR_NULL(ifp)) {
+ tmp_if = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h));
+ if (!tmp_if) {
brcmf_dbg(INFO, "no matching ifp found\n");
return -EBADE;
}
if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) !=
BCDC_PROTO_VER) {
brcmf_err("%s: non-BCDC packet received, flags 0x%x\n",
- brcmf_ifname(drvr, ifp->ifidx), h->flags);
+ brcmf_ifname(drvr, tmp_if->ifidx), h->flags);
return -EBADE;
}
if (h->flags & BCDC_FLAG_SUM_GOOD) {
brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
- brcmf_ifname(drvr, ifp->ifidx), h->flags);
+ brcmf_ifname(drvr, tmp_if->ifidx), h->flags);
pktbuf->ip_summed = CHECKSUM_UNNECESSARY;
}
@@ -312,7 +312,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
skb_pull(pktbuf, BCDC_HEADER_LEN);
if (do_fws)
- brcmf_fws_hdrpull(drvr, ifp->ifidx, h->data_offset << 2,
+ brcmf_fws_hdrpull(drvr, tmp_if->ifidx, h->data_offset << 2,
pktbuf);
else
skb_pull(pktbuf, h->data_offset << 2);
@@ -320,7 +320,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
if (pktbuf->len == 0)
return -ENODATA;
- *ifidx = ifp->ifidx;
+ *ifp = tmp_if;
return 0;
}
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -87,7 +87,7 @@ struct brcmf_if *brcmf_get_ifp(struct br
{
if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
brcmf_err("ifidx %d out of range\n", ifidx);
- return ERR_PTR(-ERANGE);
+ return NULL;
}
/* The ifidx is the idx to map to matching netdev/ifp. When receiving
@@ -539,17 +539,15 @@ void brcmf_rx_frame(struct device *dev,
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
struct brcmf_skb_reorder_data *rd;
- u8 ifidx;
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, &ifidx, skb);
- ifp = drvr->iflist[ifidx];
+ ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
if (ret || !ifp || !ifp->ndev) {
- if ((ret != -ENODATA) && ifp)
+ if (ret != -ENODATA && ifp)
ifp->stats.rx_errors++;
brcmu_pkt_buf_free_skb(skb);
return;
@@ -592,17 +590,17 @@ void brcmf_txcomplete(struct device *dev
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
- u8 ifidx;
+ struct brcmf_if *ifp;
/* await txstatus signal for firmware if active */
if (brcmf_fws_fc_active(drvr->fws)) {
if (!success)
brcmf_fws_bustxfail(drvr->fws, txp);
} else {
- if (brcmf_proto_hdrpull(drvr, false, &ifidx, txp))
+ if (brcmf_proto_hdrpull(drvr, false, txp, &ifp))
brcmu_pkt_buf_free_skb(txp);
else
- brcmf_txfinalize(drvr, txp, ifidx, success);
+ brcmf_txfinalize(drvr, txp, ifp->ifidx, success);
}
}
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -1448,7 +1448,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i
struct sk_buff *skb;
struct brcmf_skbuff_cb *skcb;
struct brcmf_fws_mac_descriptor *entry = NULL;
- u8 ifidx;
+ struct brcmf_if *ifp;
brcmf_dbg(DATA, "flags %d\n", flags);
@@ -1497,15 +1497,16 @@ brcmf_fws_txs_process(struct brcmf_fws_i
}
brcmf_fws_macdesc_return_req_credit(skb);
- if (brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb)) {
+ ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp);
+ if (ret) {
brcmu_pkt_buf_free_skb(skb);
return -EINVAL;
}
if (!remove_from_hanger)
- ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifidx,
+ ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx,
genbit, seq);
if (remove_from_hanger || ret)
- brcmf_txfinalize(fws->drvr, skb, ifidx, true);
+ brcmf_txfinalize(fws->drvr, skb, ifp->ifidx, true);
return 0;
}
@@ -1848,7 +1849,7 @@ static int brcmf_fws_commit_skb(struct b
entry->transit_count--;
if (entry->suppressed)
entry->suppr_transit_count--;
- brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
+ (void)brcmf_proto_hdrpull(fws->drvr, false, skb, NULL);
goto rollback;
}
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
@@ -522,7 +522,7 @@ static int brcmf_msgbuf_set_dcmd(struct
static int brcmf_msgbuf_hdrpull(struct brcmf_pub *drvr, bool do_fws,
- u8 *ifidx, struct sk_buff *skb)
+ struct sk_buff *skb, struct brcmf_if **ifp)
{
return -ENODEV;
}
@@ -1082,7 +1082,7 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf
struct brcmf_if *ifp;
ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
- if (IS_ERR_OR_NULL(ifp) || !ifp->ndev) {
+ if (!ifp || !ifp->ndev) {
brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
brcmu_pkt_buf_free_skb(skb);
return;
--- a/drivers/net/wireless/brcm80211/brcmfmac/proto.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.h
@@ -24,8 +24,8 @@ enum proto_addr_mode {
struct brcmf_proto {
- int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
- struct sk_buff *skb);
+ int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws,
+ struct sk_buff *skb, struct brcmf_if **ifp);
int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len);
int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
@@ -46,9 +46,19 @@ int brcmf_proto_attach(struct brcmf_pub
void brcmf_proto_detach(struct brcmf_pub *drvr);
static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,
- u8 *ifidx, struct sk_buff *skb)
+ struct sk_buff *skb,
+ struct brcmf_if **ifp)
{
- return drvr->proto->hdrpull(drvr, do_fws, ifidx, skb);
+ struct brcmf_if *tmp = NULL;
+
+ /* assure protocol is always called with
+ * non-null initialized pointer.
+ */
+ if (ifp)
+ *ifp = NULL;
+ else
+ ifp = &tmp;
+ return drvr->proto->hdrpull(drvr, do_fws, skb, ifp);
}
static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx,
uint cmd, void *buf, uint len)

View File

@ -0,0 +1,87 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:14:55 +0200
Subject: [PATCH] brcmfmac: change parameters for
brcmf_remove_interface()
Just pass the interface to be removed, ie. the struct brcmf_if instance.
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>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
@@ -4982,7 +4982,7 @@ brcmf_notify_connect_status_ap(struct br
brcmf_dbg(CONN, "AP mode link down\n");
complete(&cfg->vif_disabled);
if (ifp->vif->mbss)
- brcmf_remove_interface(ifp->drvr, ifp->bssidx);
+ brcmf_remove_interface(ifp);
return 0;
}
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -887,12 +887,13 @@ static void brcmf_del_if(struct brcmf_pu
}
}
-void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx)
+void brcmf_remove_interface(struct brcmf_if *ifp)
{
- if (drvr->iflist[bssidx]) {
- brcmf_fws_del_interface(drvr->iflist[bssidx]);
- brcmf_del_if(drvr, bssidx);
- }
+ if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bssidx] != ifp))
+ return;
+
+ brcmf_fws_del_interface(ifp);
+ brcmf_del_if(ifp->drvr, ifp->bssidx);
}
int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr)
@@ -1122,7 +1123,7 @@ void brcmf_detach(struct device *dev)
/* make sure primary interface removed last */
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
- brcmf_remove_interface(drvr, i);
+ brcmf_remove_interface(drvr->iflist[i]);
brcmf_cfg80211_detach(drvr->config);
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
@@ -206,7 +206,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 bssidx, s32 ifidx,
char *name, u8 *mac_addr);
-void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx);
+void brcmf_remove_interface(struct brcmf_if *ifp);
int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr);
void brcmf_txflowblock_if(struct brcmf_if *ifp,
enum brcmf_netif_stop_reason reason, bool state);
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -222,7 +222,7 @@ static void brcmf_fweh_handle_if_event(s
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
if (ifp && ifevent->action == BRCMF_E_IF_DEL)
- brcmf_remove_interface(drvr, ifevent->bssidx);
+ brcmf_remove_interface(ifp);
}
/**
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -2140,7 +2140,7 @@ static void brcmf_p2p_delete_p2pdev(stru
{
cfg80211_unregister_wdev(&vif->wdev);
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
- brcmf_remove_interface(vif->ifp->drvr, vif->ifp->bssidx);
+ brcmf_remove_interface(vif->ifp);
brcmf_free_vif(vif);
}

View File

@ -0,0 +1,92 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:14:56 +0200
Subject: [PATCH] brcmfmac: only call brcmf_cfg80211_detach() when attach
was successful
In brcmf_bus_start() the function brcmf_cfg80211_attach() is called which
may fail. If this happens we should not call brcmf_cfg80211_detach() in
the failure path as it will result in NULL pointer dereference:
brcmf_fweh_activate_events: Set event_msgs error (-5)
brcmf_bus_start: failed: -5
brcmf_sdio_firmware_callback: dongle is not responding
BUG: unable to handle kernel NULL pointer dereference at 0000000000000068
IP: [<ffffffff811e8f08>] kernfs_find_ns+0x18/0xd0
PGD 0
Oops: 0000 [#1] SMP
Modules linked in: brcmfmac(O) brcmutil(O) cfg80211 auth_rpcgss
CPU: 1 PID: 45 Comm: kworker/1:1 Tainted: G O
Hardware name: Dell Inc. Latitude E6410/07XJP9, BIOS A07 02/15/2011
Workqueue: events request_firmware_work_func
task: ffff880036c09ac0 ti: ffff880036dd4000 task.ti: ffff880036dd4000
RIP: 0010:[<ffffffff811e8f08>] [<ffffffff811e8f08>] kernfs_find_ns+0x18/0xd0
RSP: 0018:ffff880036dd7a28 EFLAGS: 00010246
RAX: ffff880036c09ac0 RBX: 0000000000000000 RCX: 000000007fffffff
RDX: 0000000000000000 RSI: ffffffff816578b9 RDI: 0000000000000000
RBP: ffff880036dd7a48 R08: 0000000000000000 R09: ffff880036c0b340
R10: 00000000000002ec R11: ffff880036dd7b08 R12: ffffffff816578b9
R13: 0000000000000000 R14: ffffffff816578b9 R15: ffff8800c6c87000
FS: 0000000000000000(0000) GS:ffff88012bc40000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 0000000000000068 CR3: 0000000001a0b000 CR4: 00000000000006e0
Stack:
0000000000000000 ffffffff816578b9 0000000000000000 ffff8800c0d003c8
ffff880036dd7a78 ffffffff811e8ff5 0000000ffffffff1 ffffffff81a9b060
ffff8800c789f880 ffff8800c0d00000 ffff880036dd7a98 ffffffff811ebe0d
Call Trace:
[<ffffffff811e8ff5>] kernfs_find_and_get_ns+0x35/0x60
[<ffffffff811ebe0d>] sysfs_unmerge_group+0x1d/0x60
[<ffffffff81404ef2>] dpm_sysfs_remove+0x22/0x60
[<ffffffff813f9db9>] device_del+0x49/0x240
[<ffffffff815da768>] rfkill_unregister+0x58/0xc0
[<ffffffffa06bd91b>] wiphy_unregister+0xab/0x2f0 [cfg80211]
[<ffffffffa0742fe3>] brcmf_cfg80211_detach+0x23/0x50 [brcmfmac]
[<ffffffffa074d986>] brcmf_detach+0x86/0xe0 [brcmfmac]
[<ffffffffa0757de8>] brcmf_sdio_remove+0x48/0x120 [brcmfmac]
[<ffffffffa0758ed9>] brcmf_sdiod_remove+0x29/0xd0 [brcmfmac]
[<ffffffffa0759031>] brcmf_ops_sdio_remove+0xb1/0x110 [brcmfmac]
[<ffffffffa001c267>] sdio_bus_remove+0x37/0x100 [mmc_core]
[<ffffffff813fe026>] __device_release_driver+0x96/0x130
[<ffffffff813fe0e3>] device_release_driver+0x23/0x30
[<ffffffffa0754bc8>] brcmf_sdio_firmware_callback+0x2a8/0x5d0 [brcmfmac]
[<ffffffffa074deaf>] brcmf_fw_request_nvram_done+0x15f/0x5e0 [brcmfmac]
[<ffffffff8140142f>] ? devres_add+0x3f/0x50
[<ffffffff810642b5>] ? usermodehelper_read_unlock+0x15/0x20
[<ffffffff81400000>] ? platform_match+0x70/0xa0
[<ffffffff8140f400>] request_firmware_work_func+0x30/0x60
[<ffffffff8106828c>] process_one_work+0x14c/0x3d0
[<ffffffff8106862a>] worker_thread+0x11a/0x450
[<ffffffff81068510>] ? process_one_work+0x3d0/0x3d0
[<ffffffff8106d692>] kthread+0xd2/0xf0
[<ffffffff8106d5c0>] ? kthread_create_on_node+0x180/0x180
[<ffffffff815ed35f>] ret_from_fork+0x3f/0x70
[<ffffffff8106d5c0>] ? kthread_create_on_node+0x180/0x180
Code: e9 40 fe ff ff 48 89 d8 eb 87 66 0f 1f 84 00 00 00 00 00 66 66 66 66
90 55 48 89 e5 41 56 49 89 f6 41 55 49 89 d5 31 d2 41 54 53 <0f> b7
47 68 48 8b 5f 48 66 c1 e8 05 83 e0 01 4d 85 ed 0f b6 c8
RIP [<ffffffff811e8f08>] kernfs_find_ns+0x18/0xd0
RSP <ffff880036dd7a28>
CR2: 0000000000000068
---[ end trace 87d6ec0d3fe46740 ]---
Reported-by: Daniel (Deognyoun) Kim <dekim@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>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -1049,7 +1049,10 @@ int brcmf_bus_start(struct device *dev)
fail:
if (ret < 0) {
brcmf_err("failed: %d\n", ret);
- brcmf_cfg80211_detach(drvr->config);
+ if (drvr->config) {
+ brcmf_cfg80211_detach(drvr->config);
+ drvr->config = NULL;
+ }
if (drvr->fws) {
brcmf_fws_del_interface(ifp);
brcmf_fws_deinit(drvr);

View File

@ -0,0 +1,105 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:14:57 +0200
Subject: [PATCH] brcmfmac: correct detection of p2pdev interface event
The p2pdev interface is setup in firmware resulting in a interface
event. This event has role and no-if flag. When role is p2p client
and no-if flag is set it indicates that this is the p2pdev interface.
This info is used in handling the event and adding interface in the
driver.
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>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -795,7 +795,7 @@ fail:
}
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
- char *name, u8 *mac_addr)
+ bool is_p2pdev, char *name, u8 *mac_addr)
{
struct brcmf_if *ifp;
struct net_device *ndev;
@@ -821,7 +821,7 @@ struct brcmf_if *brcmf_add_if(struct brc
}
}
- if (!brcmf_p2p_enable && bssidx == 1) {
+ if (!brcmf_p2p_enable && is_p2pdev) {
/* this is P2P_DEVICE interface */
brcmf_dbg(INFO, "allocate non-netdev interface\n");
ifp = kzalloc(sizeof(*ifp), GFP_KERNEL);
@@ -999,12 +999,12 @@ int brcmf_bus_start(struct device *dev)
brcmf_dbg(TRACE, "\n");
/* add primary networking interface */
- ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);
+ ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d", NULL);
if (IS_ERR(ifp))
return PTR_ERR(ifp);
if (brcmf_p2p_enable)
- p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL);
+ p2p_ifp = brcmf_add_if(drvr, 1, 0, false, "p2p%d", NULL);
else
p2p_ifp = NULL;
if (IS_ERR(p2p_ifp))
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
@@ -205,7 +205,7 @@ char *brcmf_ifname(struct brcmf_pub *drv
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 bssidx, s32 ifidx,
- char *name, u8 *mac_addr);
+ bool is_p2pdev, char *name, u8 *mac_addr);
void brcmf_remove_interface(struct brcmf_if *ifp);
int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr);
void brcmf_txflowblock_if(struct brcmf_if *ifp,
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -179,6 +179,7 @@ static void brcmf_fweh_handle_if_event(s
{
struct brcmf_if_event *ifevent = data;
struct brcmf_if *ifp;
+ bool is_p2pdev;
int err = 0;
brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u role: %u\n",
@@ -186,18 +187,16 @@ static void brcmf_fweh_handle_if_event(s
ifevent->flags, ifevent->role);
/* The P2P Device interface event must not be ignored
- * contrary to what firmware tells us. The only way to
- * distinguish the P2P Device is by looking at the ifidx
- * and bssidx received.
+ * contrary to what firmware tells us.
*/
- if (!(ifevent->ifidx == 0 && ifevent->bssidx == 1) &&
- (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
+ is_p2pdev = (ifevent->flags & BRCMF_E_IF_FLAG_NOIF) &&
+ ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT;
+ if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
brcmf_dbg(EVENT, "event can be ignored\n");
return;
}
if (ifevent->ifidx >= BRCMF_MAX_IFS) {
- brcmf_err("invalid interface index: %u\n",
- ifevent->ifidx);
+ brcmf_err("invalid interface index: %u\n", ifevent->ifidx);
return;
}
@@ -207,7 +206,7 @@ static void brcmf_fweh_handle_if_event(s
brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
emsg->addr);
ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx,
- emsg->ifname, emsg->addr);
+ is_p2pdev, emsg->ifname, emsg->addr);
if (IS_ERR(ifp))
return;
brcmf_fws_add_interface(ifp);

View File

@ -0,0 +1,126 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:14:58 +0200
Subject: [PATCH] brcmfmac: use brcmf_get_ifp() to map ifidx to struct
brcmf_if instance
The knowledge on how to map the interface index to a struct brcmf_if
instance is in brcmf_get_ifp() so use that function when only the
interface index is known instead of accessing brcmf_pub::iflist
directly.
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>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c
@@ -149,7 +149,7 @@ static s32 brcmf_btcoex_params_read(stru
static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci,
bool trump_sco)
{
- struct brcmf_if *ifp = btci->cfg->pub->iflist[0];
+ struct brcmf_if *ifp = brcmf_get_ifp(btci->cfg->pub, 0);
if (trump_sco && !btci->saved_regs_part2) {
/* this should reduce eSCO agressive
@@ -468,7 +468,7 @@ int brcmf_btcoex_set_mode(struct brcmf_c
{
struct brcmf_cfg80211_info *cfg = wiphy_priv(vif->wdev.wiphy);
struct brcmf_btcoex_info *btci = cfg->btcoex;
- struct brcmf_if *ifp = cfg->pub->iflist[0];
+ struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
switch (mode) {
case BRCMF_BTCOEX_DISABLED:
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
@@ -6212,7 +6212,7 @@ static void brcmf_free_wiphy(struct wiph
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
struct device *busdev)
{
- struct net_device *ndev = drvr->iflist[0]->ndev;
+ struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
struct brcmf_cfg80211_info *cfg;
struct wiphy *wiphy;
struct brcmf_cfg80211_vif *vif;
--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
@@ -121,7 +121,7 @@ static void brcmf_feat_iovar_int_set(str
void brcmf_feat_attach(struct brcmf_pub *drvr)
{
- struct brcmf_if *ifp = drvr->iflist[0];
+ struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
@@ -221,7 +221,7 @@ static void brcmf_flowring_block(struct
bus_if = dev_get_drvdata(flow->dev);
drvr = bus_if->drvr;
- ifp = drvr->iflist[ifidx];
+ ifp = brcmf_get_ifp(drvr, ifidx);
brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked);
spin_unlock_irqrestore(&flow->block_lock, flags);
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -334,7 +334,7 @@ void brcmf_fweh_attach(struct brcmf_pub
void brcmf_fweh_detach(struct brcmf_pub *drvr)
{
struct brcmf_fweh_info *fweh = &drvr->fweh;
- struct brcmf_if *ifp = drvr->iflist[0];
+ struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
s8 eventmask[BRCMF_EVENTING_MASK_LEN];
if (ifp) {
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -972,7 +972,7 @@ static void
brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
u8 if_id)
{
- struct brcmf_if *ifp = fws->drvr->iflist[!if_id ? 0 : if_id + 1];
+ struct brcmf_if *ifp = brcmf_get_ifp(fws->drvr, if_id);
if (WARN_ON(!ifp))
return;
@@ -2118,6 +2118,7 @@ static int brcmf_debugfs_fws_stats_read(
int brcmf_fws_init(struct brcmf_pub *drvr)
{
struct brcmf_fws_info *fws;
+ struct brcmf_if *ifp;
u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
int rc;
u32 mode;
@@ -2177,21 +2178,22 @@ int brcmf_fws_init(struct brcmf_pub *drv
* continue. Set mode back to none indicating not enabled.
*/
fws->fw_signals = true;
- if (brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv)) {
+ ifp = brcmf_get_ifp(drvr, 0);
+ if (brcmf_fil_iovar_int_set(ifp, "tlv", tlv)) {
brcmf_err("failed to set bdcv2 tlv signaling\n");
fws->fcmode = BRCMF_FWS_FCMODE_NONE;
fws->fw_signals = false;
}
- if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1))
+ if (brcmf_fil_iovar_int_set(ifp, "ampdu_hostreorder", 1))
brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n");
/* Enable seq number reuse, if supported */
- if (brcmf_fil_iovar_int_get(drvr->iflist[0], "wlfc_mode", &mode) == 0) {
+ if (brcmf_fil_iovar_int_get(ifp, "wlfc_mode", &mode) == 0) {
if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) {
mode = 0;
BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1);
- if (brcmf_fil_iovar_int_set(drvr->iflist[0],
+ if (brcmf_fil_iovar_int_set(ifp,
"wlfc_mode", mode) == 0) {
BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1);
}

View File

@ -0,0 +1,122 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:14:59 +0200
Subject: [PATCH] brcmfmac: pass struct brcmf_if instance in
brcmf_txfinalize()
Most call sites of brcmf_txfinalize already have struct brcmf_if
instance so pass that to brcmf_txfinalize() as the function
needs it anyway.
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>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -560,17 +560,11 @@ void brcmf_rx_frame(struct device *dev,
brcmf_netif_rx(ifp, skb);
}
-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
- bool success)
+void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
{
- struct brcmf_if *ifp;
struct ethhdr *eh;
u16 type;
- ifp = drvr->iflist[ifidx];
- if (!ifp)
- goto done;
-
eh = (struct ethhdr *)(txp->data);
type = ntohs(eh->h_proto);
@@ -582,7 +576,7 @@ void brcmf_txfinalize(struct brcmf_pub *
if (!success)
ifp->stats.tx_errors++;
-done:
+
brcmu_pkt_buf_free_skb(txp);
}
@@ -600,7 +594,7 @@ void brcmf_txcomplete(struct device *dev
if (brcmf_proto_hdrpull(drvr, false, txp, &ifp))
brcmu_pkt_buf_free_skb(txp);
else
- brcmf_txfinalize(drvr, txp, ifp->ifidx, success);
+ brcmf_txfinalize(ifp, txp, success);
}
}
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
@@ -210,8 +210,7 @@ void brcmf_remove_interface(struct brcmf
int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr);
void brcmf_txflowblock_if(struct brcmf_if *ifp,
enum brcmf_netif_stop_reason reason, bool state);
-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
- bool success);
+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);
/* Sets dongle media info (drv_version, mac address). */
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -1506,7 +1506,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i
ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx,
genbit, seq);
if (remove_from_hanger || ret)
- brcmf_txfinalize(fws->drvr, skb, ifp->ifidx, true);
+ brcmf_txfinalize(ifp, skb, true);
return 0;
}
@@ -1905,7 +1905,7 @@ int brcmf_fws_process_skb(struct brcmf_i
if (fws->avoid_queueing) {
rc = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb);
if (rc < 0)
- brcmf_txfinalize(drvr, skb, ifp->ifidx, false);
+ brcmf_txfinalize(ifp, skb, false);
return rc;
}
@@ -1929,7 +1929,7 @@ int brcmf_fws_process_skb(struct brcmf_i
brcmf_fws_schedule_deq(fws);
} else {
brcmf_err("drop skb: no hanger slot\n");
- brcmf_txfinalize(drvr, skb, ifp->ifidx, false);
+ brcmf_txfinalize(ifp, skb, false);
rc = -ENOMEM;
}
brcmf_fws_unlock(fws);
@@ -2009,8 +2009,9 @@ static void brcmf_fws_dequeue_worker(str
ret = brcmf_proto_txdata(drvr, ifidx, 0, skb);
brcmf_fws_lock(fws);
if (ret < 0)
- brcmf_txfinalize(drvr, skb, ifidx,
- false);
+ brcmf_txfinalize(brcmf_get_ifp(drvr,
+ ifidx),
+ skb, false);
if (fws->bus_flow_blocked)
break;
}
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
@@ -873,7 +873,11 @@ brcmf_msgbuf_process_txstatus(struct brc
commonring = msgbuf->flowrings[flowid];
atomic_dec(&commonring->outstanding_tx);
- brcmf_txfinalize(msgbuf->drvr, skb, tx_status->msg.ifidx, true);
+ /* Hante: i believe this was a bug as tx_status->msg.ifidx was used
+ * in brcmf_txfinalize as index in drvr->iflist. Can you confirm/deny?
+ */
+ brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx),
+ skb, true);
}

View File

@ -0,0 +1,92 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:15:00 +0200
Subject: [PATCH] brcmfmac: add mapping for interface index to bsscfg
index
Because the P2P Device interface in firmware uses the same interface
index as the primary interface we use the bsscfg index as index in the
struct brcmf_pub::iflist. However, in the data path we get the interface
index and not the bsscfg index. So we need a mapping of interface index
to bsscfg index, which can be determined upon handle adding the interface.
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>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -85,21 +85,20 @@ char *brcmf_ifname(struct brcmf_pub *drv
struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx)
{
+ struct brcmf_if *ifp;
+ s32 bssidx;
+
if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
brcmf_err("ifidx %d out of range\n", ifidx);
return NULL;
}
- /* The ifidx is the idx to map to matching netdev/ifp. When receiving
- * events this is easy because it contains the bssidx which maps
- * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
- * bssidx 1 is used for p2p0 and no data can be received or
- * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
- */
- if (ifidx)
- ifidx++;
+ ifp = NULL;
+ bssidx = drvr->if2bss[ifidx];
+ if (bssidx >= 0)
+ ifp = drvr->iflist[bssidx];
- return drvr->iflist[ifidx];
+ return ifp;
}
static void _brcmf_set_multicast_list(struct work_struct *work)
@@ -831,6 +830,8 @@ struct brcmf_if *brcmf_add_if(struct brc
ifp = netdev_priv(ndev);
ifp->ndev = ndev;
+ /* store mapping ifidx to bssidx */
+ drvr->if2bss[ifidx] = bssidx;
}
ifp->drvr = drvr;
@@ -855,6 +856,7 @@ static void brcmf_del_if(struct brcmf_pu
struct brcmf_if *ifp;
ifp = drvr->iflist[bssidx];
+ drvr->if2bss[ifp->ifidx] = -1;
drvr->iflist[bssidx] = NULL;
if (!ifp) {
brcmf_err("Null interface, idx=%d\n", bssidx);
@@ -862,6 +864,7 @@ static void brcmf_del_if(struct brcmf_pu
}
brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx);
if (ifp->ndev) {
+ drvr->if2bss[ifp->ifidx] = -1;
if (bssidx == 0) {
if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
rtnl_lock();
@@ -926,6 +929,7 @@ int brcmf_attach(struct device *dev)
if (!drvr)
return -ENOMEM;
+ memset(drvr->if2bss, 0xFF, sizeof(drvr->if2bss));
mutex_init(&drvr->proto_block);
/* Link to bus module */
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
@@ -122,6 +122,7 @@ struct brcmf_pub {
struct mac_address addresses[BRCMF_MAX_IFS];
struct brcmf_if *iflist[BRCMF_MAX_IFS];
+ s32 if2bss[BRCMF_MAX_IFS];
struct mutex proto_block;
unsigned char proto_buf[BRCMF_DCMD_MAXLEN];

View File

@ -0,0 +1,103 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:15:01 +0200
Subject: [PATCH] brcmfmac: add dedicated debug level for firmware
console logging
Both PCIe and SDIO devices have the possibility to log the firmware
console output in kernel log. For PCIe it is logged when PCIE debug
level is enabled. For SDIO it is logged when user specifies a non-zero
console interval through debugfs. This patch tries to make it a
bit more consistent. The firmware console output is only logged when
FWCON debug level is enabled.
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>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.h
@@ -37,6 +37,7 @@
#define BRCMF_SDIO_VAL 0x00020000
#define BRCMF_MSGBUF_VAL 0x00040000
#define BRCMF_PCIE_VAL 0x00080000
+#define BRCMF_FWCON_VAL 0x00100000
/* set default print format */
#undef pr_fmt
@@ -78,6 +79,7 @@ do { \
#define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL)
#define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL)
#define BRCMF_FIL_ON() (brcmf_msg_level & BRCMF_FIL_VAL)
+#define BRCMF_FWCON_ON() (brcmf_msg_level & BRCMF_FWCON_VAL)
#else /* defined(DEBUG) || defined(CPTCFG_BRCM_TRACING) */
@@ -90,6 +92,7 @@ do { \
#define BRCMF_GLOM_ON() 0
#define BRCMF_EVENT_ON() 0
#define BRCMF_FIL_ON() 0
+#define BRCMF_FWCON_ON() 0
#endif /* defined(DEBUG) || defined(CPTCFG_BRCM_TRACING) */
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
@@ -644,7 +644,7 @@ static void brcmf_pcie_bus_console_init(
addr = console->base_addr + BRCMF_CONSOLE_BUFSIZE_OFFSET;
console->bufsize = brcmf_pcie_read_tcm32(devinfo, addr);
- brcmf_dbg(PCIE, "Console: base %x, buf %x, size %d\n",
+ brcmf_dbg(FWCON, "Console: base %x, buf %x, size %d\n",
console->base_addr, console->buf_addr, console->bufsize);
}
@@ -656,6 +656,9 @@ static void brcmf_pcie_bus_console_read(
u8 ch;
u32 newidx;
+ if (!BRCMF_FWCON_ON())
+ return;
+
console = &devinfo->shared.console;
addr = console->base_addr + BRCMF_CONSOLE_WRITEIDX_OFFSET;
newidx = brcmf_pcie_read_tcm32(devinfo, addr);
@@ -677,7 +680,7 @@ static void brcmf_pcie_bus_console_read(
}
if (ch == '\n') {
console->log_str[console->log_idx] = 0;
- brcmf_dbg(PCIE, "CONSOLE: %s", console->log_str);
+ pr_debug("CONSOLE: %s", console->log_str);
console->log_idx = 0;
}
}
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
@@ -123,6 +123,7 @@ struct rte_console {
#define BRCMF_FIRSTREAD (1 << 6)
+#define BRCMF_CONSOLE 10 /* watchdog interval to poll console */
/* SBSDIO_DEVICE_CTL */
@@ -3204,6 +3205,8 @@ static void brcmf_sdio_debugfs_create(st
if (IS_ERR_OR_NULL(dentry))
return;
+ bus->console_interval = BRCMF_CONSOLE;
+
brcmf_debugfs_add_entry(drvr, "forensics", brcmf_sdio_forensic_read);
brcmf_debugfs_add_entry(drvr, "counters",
brcmf_debugfs_sdio_count_read);
@@ -3613,7 +3616,7 @@ static void brcmf_sdio_bus_watchdog(stru
}
#ifdef DEBUG
/* Poll for console output periodically */
- if (bus->sdiodev->state == BRCMF_SDIOD_DATA &&
+ if (bus->sdiodev->state == BRCMF_SDIOD_DATA && BRCMF_FWCON_ON() &&
bus->console_interval != 0) {
bus->console.count += BRCMF_WD_POLL_MS;
if (bus->console.count >= bus->console_interval) {

View File

@ -0,0 +1,34 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:15:02 +0200
Subject: [PATCH] brcmfmac: remove ifidx parameter from
brcmf_fws_txstatus_suppressed()
The brcmf_fws_txstatus_suppressed() function prototype specifies an
ifidx parameter which is not used within the function implementation.
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>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -1398,7 +1398,7 @@ done:
}
static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
- struct sk_buff *skb, u8 ifidx,
+ struct sk_buff *skb,
u32 genbit, u16 seq)
{
struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
@@ -1503,7 +1503,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i
return -EINVAL;
}
if (!remove_from_hanger)
- ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx,
+ ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb,
genbit, seq);
if (remove_from_hanger || ret)
brcmf_txfinalize(ifp, skb, true);

View File

@ -0,0 +1,97 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:15:03 +0200
Subject: [PATCH] brcmfmac: change prototype for brcmf_fws_hdrpull()
Instead of passing ifidx and drvr just pass struct brcmf_if pointer
which holds both parameters.
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>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
@@ -312,8 +312,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu
skb_pull(pktbuf, BCDC_HEADER_LEN);
if (do_fws)
- brcmf_fws_hdrpull(drvr, tmp_if->ifidx, h->data_offset << 2,
- pktbuf);
+ brcmf_fws_hdrpull(tmp_if, h->data_offset << 2, pktbuf);
else
skb_pull(pktbuf, h->data_offset << 2);
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -1616,11 +1616,10 @@ static int brcmf_fws_notify_bcmc_credit_
return 0;
}
-int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
- struct sk_buff *skb)
+void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
{
struct brcmf_skb_reorder_data *rd;
- struct brcmf_fws_info *fws = drvr->fws;
+ struct brcmf_fws_info *fws = ifp->drvr->fws;
u8 *signal_data;
s16 data_len;
u8 type;
@@ -1630,20 +1629,20 @@ int brcmf_fws_hdrpull(struct brcmf_pub *
s32 err;
brcmf_dbg(HDRS, "enter: ifidx %d, skblen %u, sig %d\n",
- ifidx, skb->len, signal_len);
+ ifp->ifidx, skb->len, siglen);
- WARN_ON(signal_len > skb->len);
+ WARN_ON(siglen > skb->len);
- if (!signal_len)
- return 0;
+ if (!siglen)
+ return;
/* if flow control disabled, skip to packet data and leave */
if ((!fws) || (!fws->fw_signals)) {
- skb_pull(skb, signal_len);
- return 0;
+ skb_pull(skb, siglen);
+ return;
}
fws->stats.header_pulls++;
- data_len = signal_len;
+ data_len = siglen;
signal_data = skb->data;
status = BRCMF_FWS_RET_OK_NOSCHEDULE;
@@ -1731,14 +1730,12 @@ int brcmf_fws_hdrpull(struct brcmf_pub *
/* signalling processing result does
* not affect the actual ethernet packet.
*/
- skb_pull(skb, signal_len);
+ skb_pull(skb, siglen);
/* this may be a signal-only packet
*/
if (skb->len == 0)
fws->stats.header_only_pkt++;
-
- return 0;
}
static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
@@ -21,8 +21,7 @@
int brcmf_fws_init(struct brcmf_pub *drvr);
void brcmf_fws_deinit(struct brcmf_pub *drvr);
bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
-int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
- struct sk_buff *skb);
+void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb);
int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb);
void brcmf_fws_reset_interface(struct brcmf_if *ifp);

View File

@ -0,0 +1,99 @@
From: Arend van Spriel <arend@broadcom.com>
Date: Wed, 26 Aug 2015 22:15:04 +0200
Subject: [PATCH] brcmfmac: introduce brcmf_net_detach() function
In case of error during brcmf_bus_start() the network interfaces were
freed using free_netdev(). However, the interfaces may have additional
memory allocated which is not freed. The netdev has destructor set to
brcmf_cfg80211_free_netdev() which frees the additional memory if
allocated and call free_netdev(). The brcmf_net_detach() either calls
brcmf_cfg80211_free_netdev() directly or uses unregister_netdev() when
struct net_device::reg_state indicates the netdev was registered.
Reported-by: Daniel (Deognyoun) Kim <dekim@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>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
@@ -4746,7 +4746,8 @@ void brcmf_cfg80211_free_netdev(struct n
ifp = netdev_priv(ndev);
vif = ifp->vif;
- brcmf_free_vif(vif);
+ if (vif)
+ brcmf_free_vif(vif);
free_netdev(ndev);
}
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -718,8 +718,6 @@ int brcmf_net_attach(struct brcmf_if *if
}
brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
-
- ndev->destructor = brcmf_cfg80211_free_netdev;
return 0;
fail:
@@ -729,6 +727,14 @@ fail:
return -EBADE;
}
+static void brcmf_net_detach(struct net_device *ndev)
+{
+ if (ndev->reg_state == NETREG_REGISTERED)
+ unregister_netdev(ndev);
+ else
+ brcmf_cfg80211_free_netdev(ndev);
+}
+
static int brcmf_net_p2p_open(struct net_device *ndev)
{
brcmf_dbg(TRACE, "Enter\n");
@@ -805,8 +811,7 @@ struct brcmf_if *brcmf_add_if(struct brc
ifp->ndev->name);
if (ifidx) {
netif_stop_queue(ifp->ndev);
- unregister_netdev(ifp->ndev);
- free_netdev(ifp->ndev);
+ brcmf_net_detach(ifp->ndev);
drvr->iflist[bssidx] = NULL;
} else {
brcmf_err("ignore IF event\n");
@@ -828,6 +833,7 @@ struct brcmf_if *brcmf_add_if(struct brc
if (!ndev)
return ERR_PTR(-ENOMEM);
+ ndev->destructor = brcmf_cfg80211_free_netdev;
ifp = netdev_priv(ndev);
ifp->ndev = ndev;
/* store mapping ifidx to bssidx */
@@ -879,8 +885,7 @@ static void brcmf_del_if(struct brcmf_pu
cancel_work_sync(&ifp->setmacaddr_work);
cancel_work_sync(&ifp->multicast_work);
}
- /* unregister will take care of freeing it */
- unregister_netdev(ifp->ndev);
+ brcmf_net_detach(ifp->ndev);
}
}
@@ -1056,11 +1061,11 @@ fail:
brcmf_fws_deinit(drvr);
}
if (drvr->iflist[0]) {
- free_netdev(ifp->ndev);
+ brcmf_net_detach(ifp->ndev);
drvr->iflist[0] = NULL;
}
if (p2p_ifp) {
- free_netdev(p2p_ifp->ndev);
+ brcmf_net_detach(p2p_ifp->ndev);
drvr->iflist[1] = NULL;
}
return ret;

View File

@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -1189,6 +1189,7 @@ static int __init brcmfmac_module_init(v
@@ -1213,6 +1213,7 @@ static int __init brcmfmac_module_init(v
#endif
if (!schedule_work(&brcmf_driver_work))
return -EBUSY;

View File

@ -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
@@ -661,8 +661,36 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
@@ -691,9 +691,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) {