--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:04 +0200
+Subject: [PATCH] brcmfmac: Fix exception handling.
+
+In some exception situations the ifp->vif was not properly assigned
+which could result in crash.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -6331,6 +6331,7 @@ wiphy_unreg_out:
+ priv_out:
+ wl_deinit_priv(cfg);
+ brcmf_free_vif(vif);
++ ifp->vif = NULL;
+ wiphy_out:
+ brcmf_free_wiphy(wiphy);
+ return NULL;
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:05 +0200
+Subject: [PATCH] brcmfmac: Add support for the BCM4350 PCIE device.
+
+This patch adds support fo the BRCM4350 2x2 11ac PCIE device.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/chip.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
+@@ -647,6 +647,7 @@ static u32 brcmf_chip_tcm_rambase(struct
+ return 0x198000;
+ case BRCM_CC_4335_CHIP_ID:
+ case BRCM_CC_4339_CHIP_ID:
++ case BRCM_CC_4350_CHIP_ID:
+ case BRCM_CC_4354_CHIP_ID:
+ case BRCM_CC_4356_CHIP_ID:
+ case BRCM_CC_43567_CHIP_ID:
+--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+@@ -47,6 +47,8 @@ enum brcmf_pcie_state {
+
+ #define BRCMF_PCIE_43602_FW_NAME "brcm/brcmfmac43602-pcie.bin"
+ #define BRCMF_PCIE_43602_NVRAM_NAME "brcm/brcmfmac43602-pcie.txt"
++#define BRCMF_PCIE_4350_FW_NAME "brcm/brcmfmac4350-pcie.bin"
++#define BRCMF_PCIE_4350_NVRAM_NAME "brcm/brcmfmac4350-pcie.txt"
+ #define BRCMF_PCIE_4356_FW_NAME "brcm/brcmfmac4356-pcie.bin"
+ #define BRCMF_PCIE_4356_NVRAM_NAME "brcm/brcmfmac4356-pcie.txt"
+ #define BRCMF_PCIE_43570_FW_NAME "brcm/brcmfmac43570-pcie.bin"
+@@ -194,6 +196,8 @@ enum brcmf_pcie_state {
+
+ MODULE_FIRMWARE(BRCMF_PCIE_43602_FW_NAME);
+ MODULE_FIRMWARE(BRCMF_PCIE_43602_NVRAM_NAME);
++MODULE_FIRMWARE(BRCMF_PCIE_4350_FW_NAME);
++MODULE_FIRMWARE(BRCMF_PCIE_4350_NVRAM_NAME);
+ MODULE_FIRMWARE(BRCMF_PCIE_4356_FW_NAME);
+ MODULE_FIRMWARE(BRCMF_PCIE_4356_NVRAM_NAME);
+ MODULE_FIRMWARE(BRCMF_PCIE_43570_FW_NAME);
+@@ -1418,6 +1422,10 @@ static int brcmf_pcie_get_fwnames(struct
+ fw_name = BRCMF_PCIE_43602_FW_NAME;
+ nvram_name = BRCMF_PCIE_43602_NVRAM_NAME;
+ break;
++ case BRCM_CC_4350_CHIP_ID:
++ fw_name = BRCMF_PCIE_4350_FW_NAME;
++ nvram_name = BRCMF_PCIE_4350_NVRAM_NAME;
++ break;
+ case BRCM_CC_4356_CHIP_ID:
+ fw_name = BRCMF_PCIE_4356_FW_NAME;
+ nvram_name = BRCMF_PCIE_4356_NVRAM_NAME;
+@@ -1956,6 +1964,7 @@ cleanup:
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
+
+ static struct pci_device_id brcmf_pcie_devid_table[] = {
++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID),
+--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
++++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
+@@ -39,6 +39,7 @@
+ #define BRCM_CC_4339_CHIP_ID 0x4339
+ #define BRCM_CC_43430_CHIP_ID 43430
+ #define BRCM_CC_4345_CHIP_ID 0x4345
++#define BRCM_CC_4350_CHIP_ID 0x4350
+ #define BRCM_CC_4354_CHIP_ID 0x4354
+ #define BRCM_CC_4356_CHIP_ID 0x4356
+ #define BRCM_CC_43566_CHIP_ID 43566
+@@ -56,6 +57,7 @@
+ #define BRCM_USB_BCMFW_DEVICE_ID 0x0bdc
+
+ /* PCIE Device IDs */
++#define BRCM_PCIE_4350_DEVICE_ID 0x43a3
+ #define BRCM_PCIE_4354_DEVICE_ID 0x43df
+ #define BRCM_PCIE_4356_DEVICE_ID 0x43ec
+ #define BRCM_PCIE_43567_DEVICE_ID 0x43d3
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:06 +0200
+Subject: [PATCH] brcmfmac: Fix set and get tx-power functions.
+
+Implementation of tx-power (get and set) related functions are
+still assuming mW interface. This is wrong as functions use dbm
+(or mbm) nowadays. As a result a tx power configuration could
+result in wrong power configuration.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -236,89 +236,6 @@ static int brcmf_roamoff;
+ module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
+ MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
+
+-/* Quarter dBm units to mW
+- * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
+- * Table is offset so the last entry is largest mW value that fits in
+- * a u16.
+- */
+-
+-#define QDBM_OFFSET 153 /* Offset for first entry */
+-#define QDBM_TABLE_LEN 40 /* Table size */
+-
+-/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
+- * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
+- */
+-#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
+-
+-/* Largest mW value that will round down to the last table entry,
+- * QDBM_OFFSET + QDBM_TABLE_LEN-1.
+- * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
+- * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
+- */
+-#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
+-
+-static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
+-/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
+-/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
+-/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
+-/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
+-/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
+-/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
+-};
+-
+-static u16 brcmf_qdbm_to_mw(u8 qdbm)
+-{
+- uint factor = 1;
+- int idx = qdbm - QDBM_OFFSET;
+-
+- if (idx >= QDBM_TABLE_LEN)
+- /* clamp to max u16 mW value */
+- return 0xFFFF;
+-
+- /* scale the qdBm index up to the range of the table 0-40
+- * where an offset of 40 qdBm equals a factor of 10 mW.
+- */
+- while (idx < 0) {
+- idx += 40;
+- factor *= 10;
+- }
+-
+- /* return the mW value scaled down to the correct factor of 10,
+- * adding in factor/2 to get proper rounding.
+- */
+- return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
+-}
+-
+-static u8 brcmf_mw_to_qdbm(u16 mw)
+-{
+- u8 qdbm;
+- int offset;
+- uint mw_uint = mw;
+- uint boundary;
+-
+- /* handle boundary case */
+- if (mw_uint <= 1)
+- return 0;
+-
+- offset = QDBM_OFFSET;
+-
+- /* move mw into the range of the table */
+- while (mw_uint < QDBM_TABLE_LOW_BOUND) {
+- mw_uint *= 10;
+- offset -= 40;
+- }
+-
+- for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
+- boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
+- nqdBm_to_mW_map[qdbm]) / 2;
+- if (mw_uint < boundary)
+- break;
+- }
+-
+- qdbm += (u8) offset;
+-
+- return qdbm;
+-}
+
+ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
+ struct cfg80211_chan_def *ch)
+@@ -2016,16 +1933,14 @@ static s32
+ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_tx_power_setting type, s32 mbm)
+ {
+-
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = cfg_to_ndev(cfg);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+- u16 txpwrmw;
+- s32 err = 0;
+- s32 disable = 0;
+- s32 dbm = MBM_TO_DBM(mbm);
++ s32 err;
++ s32 disable;
++ u32 qdbm = 127;
+
+- brcmf_dbg(TRACE, "Enter\n");
++ brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+@@ -2034,12 +1949,20 @@ brcmf_cfg80211_set_tx_power(struct wiphy
+ break;
+ case NL80211_TX_POWER_LIMITED:
+ case NL80211_TX_POWER_FIXED:
+- if (dbm < 0) {
++ if (mbm < 0) {
+ brcmf_err("TX_POWER_FIXED - dbm is negative\n");
+ err = -EINVAL;
+ goto done;
+ }
++ qdbm = MBM_TO_DBM(4 * mbm);
++ if (qdbm > 127)
++ qdbm = 127;
++ qdbm |= WL_TXPWR_OVERRIDE;
+ break;
++ default:
++ brcmf_err("Unsupported type %d\n", type);
++ err = -EINVAL;
++ goto done;
+ }
+ /* Make sure radio is off or on as far as software is concerned */
+ disable = WL_RADIO_SW_DISABLE << 16;
+@@ -2047,52 +1970,44 @@ brcmf_cfg80211_set_tx_power(struct wiphy
+ if (err)
+ brcmf_err("WLC_SET_RADIO error (%d)\n", err);
+
+- if (dbm > 0xffff)
+- txpwrmw = 0xffff;
+- else
+- txpwrmw = (u16) dbm;
+- err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
+- (s32)brcmf_mw_to_qdbm(txpwrmw));
++ err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
+ if (err)
+ brcmf_err("qtxpower error (%d)\n", err);
+- cfg->conf->tx_power = dbm;
+
+ done:
+- brcmf_dbg(TRACE, "Exit\n");
++ brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
+ return err;
+ }
+
+-static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
+- struct wireless_dev *wdev,
+- s32 *dbm)
++static s32
++brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
++ s32 *dbm)
+ {
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+- s32 txpwrdbm;
+- u8 result;
+- s32 err = 0;
++ struct net_device *ndev = cfg_to_ndev(cfg);
++ struct brcmf_if *ifp = netdev_priv(ndev);
++ s32 qdbm = 0;
++ s32 err;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+- err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
++ err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
+ if (err) {
+ brcmf_err("error (%d)\n", err);
+ goto done;
+ }
+-
+- result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
+- *dbm = (s32) brcmf_qdbm_to_mw(result);
++ *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
+
+ done:
+- brcmf_dbg(TRACE, "Exit\n");
++ brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
+ return err;
+ }
+
+ static s32
+ brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
+- u8 key_idx, bool unicast, bool multicast)
++ u8 key_idx, bool unicast, bool multicast)
+ {
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ u32 index;
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:07 +0200
+Subject: [PATCH] brcmfmac: Only assign primary netdev to if2bss array.
+
+The if2bss allows for translation of ifidx to bssidx which has a 1:n
+relation. Therefor only the first (primary) netdev should be
+assigned in this array. This fixes the p2pon=1 module param usage.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -53,6 +53,8 @@ MODULE_LICENSE("Dual BSD/GPL");
+ #define BRCMF_RXREORDER_EXPIDX_VALID 0x08
+ #define BRCMF_RXREORDER_NEW_HOLE 0x10
+
++#define BRCMF_BSSIDX_INVALID -1
++
+ /* Error bits */
+ int brcmf_msg_level;
+ module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR);
+@@ -837,7 +839,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;
++ if (drvr->if2bss[ifidx] == BRCMF_BSSIDX_INVALID)
++ drvr->if2bss[ifidx] = bssidx;
+ }
+
+ ifp->drvr = drvr;
+@@ -862,15 +865,15 @@ 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);
+ return;
+ }
+ brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx);
++ if (drvr->if2bss[ifp->ifidx] == bssidx)
++ drvr->if2bss[ifp->ifidx] = BRCMF_BSSIDX_INVALID;
+ 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)
+ {
+ struct brcmf_pub *drvr = NULL;
+ int ret = 0;
++ int i;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+@@ -934,7 +938,9 @@ int brcmf_attach(struct device *dev)
+ if (!drvr)
+ return -ENOMEM;
+
+- memset(drvr->if2bss, 0xFF, sizeof(drvr->if2bss));
++ for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++)
++ drvr->if2bss[i] = BRCMF_BSSIDX_INVALID;
++
+ mutex_init(&drvr->proto_block);
+
+ /* Link to bus module */
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:08 +0200
+Subject: [PATCH] brcmfmac: Inform p2p module about p2pon through API
+
+When the p2pon module param is used then p2p attach will initialize
+p2p device iface in the firmware, but it is doing that by checking
+data. It is cleaner to pass the p2pon information to p2p by API.
+This information is also needed for other patch.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -6126,7 +6126,8 @@ static void brcmf_free_wiphy(struct wiph
+ }
+
+ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
+- struct device *busdev)
++ struct device *busdev,
++ bool p2pdev_forced)
+ {
+ struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
+ struct brcmf_cfg80211_info *cfg;
+@@ -6218,7 +6219,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+ *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
+
+- err = brcmf_p2p_attach(cfg);
++ err = brcmf_p2p_attach(cfg, p2pdev_forced);
+ if (err) {
+ brcmf_err("P2P initilisation failed (%d)\n", err);
+ goto wiphy_unreg_out;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h
+@@ -469,7 +469,8 @@ brcmf_cfg80211_connect_info *cfg_to_conn
+ }
+
+ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
+- struct device *busdev);
++ struct device *busdev,
++ bool p2pdev_forced);
+ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
+ s32 brcmf_cfg80211_up(struct net_device *ndev);
+ s32 brcmf_cfg80211_down(struct net_device *ndev);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -1044,7 +1044,8 @@ int brcmf_bus_start(struct device *dev)
+
+ brcmf_fws_add_interface(ifp);
+
+- drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
++ drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev,
++ brcmf_p2p_enable);
+ if (drvr->config == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+@@ -2333,7 +2333,7 @@ void brcmf_p2p_stop_device(struct wiphy
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ */
+-s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
++s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced)
+ {
+ struct brcmf_if *pri_ifp;
+ struct brcmf_if *p2p_ifp;
+@@ -2348,11 +2348,15 @@ s32 brcmf_p2p_attach(struct brcmf_cfg802
+
+ drvr = cfg->pub;
+
+- pri_ifp = drvr->iflist[0];
+- p2p_ifp = drvr->iflist[1];
+-
++ pri_ifp = brcmf_get_ifp(drvr, 0);
+ p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
+
++ if (p2pdev_forced) {
++ p2p_ifp = drvr->iflist[1];
++ } else {
++ p2p_ifp = NULL;
++ p2p->p2pdev_dynamically = true;
++ }
+ if (p2p_ifp) {
+ p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
+ false);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
+@@ -124,6 +124,7 @@ struct afx_hdl {
+ * @wait_next_af: thread synchronizing struct.
+ * @gon_req_action: about to send go negotiation requets frame.
+ * @block_gon_req_tx: drop tx go negotiation requets frame.
++ * @p2pdev_dynamically: is p2p device if created by module param or supplicant.
+ */
+ struct brcmf_p2p_info {
+ struct brcmf_cfg80211_info *cfg;
+@@ -144,9 +145,10 @@ struct brcmf_p2p_info {
+ struct completion wait_next_af;
+ bool gon_req_action;
+ bool block_gon_req_tx;
++ bool p2pdev_dynamically;
+ };
+
+-s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg);
++s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced);
+ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p);
+ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
+ enum nl80211_iftype type, u32 *flags,
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:09 +0200
+Subject: [PATCH] brcmfmac: Fix bug in flowring management.
+
+The hash index stored in the flowrings is of type u16 but gets
+stored in u8. This can result in incorrect indexing and possibly
+result in crashes. This patch fixes the type.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/flowring.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
+@@ -34,7 +34,7 @@ enum ring_status {
+ };
+
+ struct brcmf_flowring_ring {
+- u8 hash_id;
++ u16 hash_id;
+ bool blocked;
+ enum ring_status status;
+ struct sk_buff_head skblist;
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:10 +0200
+Subject: [PATCH] brcmfmac: Make p2pon module param always available.
+
+p2pon module param is currently under define BRCMDBG. Though it is
+a needed option for older versions of the wpa_supplicant which do not
+support the P2P_DEVICE interface.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -62,10 +62,8 @@ MODULE_PARM_DESC(debug, "level of debug
+
+ /* P2P0 enable */
+ static int brcmf_p2p_enable;
+-#ifdef CPTCFG_BRCMDBG
+ module_param_named(p2pon, brcmf_p2p_enable, int, 0);
+-MODULE_PARM_DESC(p2pon, "enable p2p management functionality");
+-#endif
++MODULE_PARM_DESC(p2pon, "enable legacy p2p management functionality");
+
+ char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
+ {
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:11 +0200
+Subject: [PATCH] brcmfmac: Workaround in change vif for wpa_supplicant
+ support.
+
+Different wpa_supplicants have different behavior and expectations
+regarding the change_virtual_intf behavior. This patch implements
+a workaround for the different versions and possible brcmfmac
+configuration.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -776,6 +776,37 @@ brcmf_cfg80211_change_iface(struct wiphy
+ s32 err = 0;
+
+ brcmf_dbg(TRACE, "Enter, idx=%d, type=%d\n", ifp->bssidx, type);
++
++ /* WAR: There are a number of p2p interface related problems which
++ * need to be handled initially (before doing the validate).
++ * wpa_supplicant tends to do iface changes on p2p device/client/go
++ * which are not always possible/allowed. However we need to return
++ * OK otherwise the wpa_supplicant wont start. The situation differs
++ * on configuration and setup (p2pon=1 module param). The first check
++ * is to see if the request is a change to station for p2p iface.
++ */
++ if ((type == NL80211_IFTYPE_STATION) &&
++ ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
++ (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ||
++ (vif->wdev.iftype == NL80211_IFTYPE_P2P_DEVICE))) {
++ brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
++ /* Now depending on whether module param p2pon=1 was used the
++ * response needs to be either 0 or EOPNOTSUPP. The reason is
++ * that if p2pon=1 is used, but a newer supplicant is used then
++ * we should return an error, as this combination wont work.
++ * In other situations 0 is returned and supplicant will start
++ * normally. It will give a trace in cfg80211, but it is the
++ * only way to get it working. Unfortunately this will result
++ * in situation where we wont support new supplicant in
++ * combination with module param p2pon=1, but that is the way
++ * it is. If the user tries this then unloading of driver might
++ * fail/lock.
++ */
++ if (cfg->p2p.p2pdev_dynamically)
++ return -EOPNOTSUPP;
++ else
++ return 0;
++ }
+ err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type);
+ if (err) {
+ brcmf_err("iface validation failed: err=%d\n", err);
+@@ -791,18 +822,6 @@ brcmf_cfg80211_change_iface(struct wiphy
+ infra = 0;
+ break;
+ case NL80211_IFTYPE_STATION:
+- /* Ignore change for p2p IF. Unclear why supplicant does this */
+- if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
+- (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
+- brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
+- /* WAR: It is unexpected to get a change of VIF for P2P
+- * IF, but it happens. The request can not be handled
+- * but returning EPERM causes a crash. Returning 0
+- * without setting ieee80211_ptr->iftype causes trace
+- * (WARN_ON) but it works with wpa_supplicant
+- */
+- return 0;
+- }
+ infra = 1;
+ break;
+ case NL80211_IFTYPE_AP:
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:12 +0200
+Subject: [PATCH] brcmfmac: Deleting of p2p device is leaking memory.
+
+When a p2p device gets deleted, the memory for the vif is not being
+released. This is solved by reorganizing the cleanup path and
+properly freeing the memory.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -887,6 +887,16 @@ static void brcmf_del_if(struct brcmf_pu
+ cancel_work_sync(&ifp->multicast_work);
+ }
+ brcmf_net_detach(ifp->ndev);
++ } else {
++ /* Only p2p device interfaces which get dynamically created
++ * end up here. In this case the p2p module should be informed
++ * about the removal of the interface within the firmware. If
++ * not then p2p commands towards the firmware will cause some
++ * serious troublesome side effects. The p2p module will clean
++ * up the ifp if needed.
++ */
++ brcmf_p2p_ifp_removed(ifp);
++ kfree(ifp);
+ }
+ }
+
+@@ -894,7 +904,8 @@ void brcmf_remove_interface(struct brcmf
+ {
+ if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bssidx] != ifp))
+ return;
+-
++ brcmf_dbg(TRACE, "Enter, bssidx=%d, ifidx=%d\n", ifp->bssidx,
++ ifp->ifidx);
+ brcmf_fws_del_interface(ifp);
+ brcmf_del_if(ifp->drvr, ifp->bssidx);
+ }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+@@ -2131,20 +2131,6 @@ fail:
+ }
+
+ /**
+- * brcmf_p2p_delete_p2pdev() - delete P2P_DEVICE virtual interface.
+- *
+- * @vif: virtual interface object to delete.
+- */
+-static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p,
+- struct brcmf_cfg80211_vif *vif)
+-{
+- cfg80211_unregister_wdev(&vif->wdev);
+- p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+- brcmf_remove_interface(vif->ifp);
+- brcmf_free_vif(vif);
+-}
+-
+-/**
+ * brcmf_p2p_add_vif() - create a new P2P virtual interface.
+ *
+ * @wiphy: wiphy device of new interface.
+@@ -2264,9 +2250,11 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
+ break;
+
+ case NL80211_IFTYPE_P2P_DEVICE:
++ if (!p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
++ return 0;
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+ brcmf_p2p_deinit_discovery(p2p);
+- brcmf_p2p_delete_p2pdev(p2p, vif);
++ brcmf_remove_interface(vif->ifp);
+ return 0;
+ default:
+ return -ENOTSUPP;
+@@ -2298,6 +2286,21 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
+ return err;
+ }
+
++void brcmf_p2p_ifp_removed(struct brcmf_if *ifp)
++{
++ struct brcmf_cfg80211_info *cfg;
++ struct brcmf_cfg80211_vif *vif;
++
++ brcmf_dbg(INFO, "P2P: device interface removed\n");
++ vif = ifp->vif;
++ cfg = wdev_to_cfg(&vif->wdev);
++ cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
++ rtnl_lock();
++ cfg80211_unregister_wdev(&vif->wdev);
++ rtnl_unlock();
++ brcmf_free_vif(vif);
++}
++
+ int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev)
+ {
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+@@ -2422,10 +2425,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_i
+ if (vif != NULL) {
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+ brcmf_p2p_deinit_discovery(p2p);
+- /* remove discovery interface */
+- rtnl_lock();
+- brcmf_p2p_delete_p2pdev(p2p, vif);
+- rtnl_unlock();
++ brcmf_remove_interface(vif->ifp);
+ }
+ /* just set it all to zero */
+ memset(p2p, 0, sizeof(*p2p));
+--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
+@@ -156,6 +156,7 @@ struct wireless_dev *brcmf_p2p_add_vif(s
+ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev);
+ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
+ enum brcmf_fil_p2p_if_types if_type);
++void brcmf_p2p_ifp_removed(struct brcmf_if *ifp);
+ int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+ void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+ int brcmf_p2p_scan_prep(struct wiphy *wiphy,
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:13 +0200
+Subject: [PATCH] brcmfmac: Only handle p2p_stop_device if vif is valid
+
+In some situations it is possible that vif has been removed while
+cfg80211 invokes the p2p_stop_device handler. This will result in
+crash.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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
+@@ -2324,11 +2324,17 @@ void brcmf_p2p_stop_device(struct wiphy
+ struct brcmf_cfg80211_vif *vif;
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+- mutex_lock(&cfg->usr_sync);
+- (void)brcmf_p2p_deinit_discovery(p2p);
+- brcmf_abort_scanning(cfg);
+- clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
+- mutex_unlock(&cfg->usr_sync);
++ /* This call can be result of the unregister_wdev call. In that case
++ * we dont want to do anything anymore. Just return. The config vif
++ * will have been cleared at this point.
++ */
++ if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif == vif) {
++ mutex_lock(&cfg->usr_sync);
++ (void)brcmf_p2p_deinit_discovery(p2p);
++ brcmf_abort_scanning(cfg);
++ clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
++ mutex_unlock(&cfg->usr_sync);
++ }
+ }
+
+ /**
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:14 +0200
+Subject: [PATCH] brcmfmac: Fix p2p bug for older firmwares.
+
+Some devices with older firmwares are reporting new p2p device
+interface with the wrong type. Accept this type to get p2p
+working for these devices.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/fweh.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+@@ -186,11 +186,13 @@ static void brcmf_fweh_handle_if_event(s
+ ifevent->action, ifevent->ifidx, ifevent->bssidx,
+ ifevent->flags, ifevent->role);
+
+- /* The P2P Device interface event must not be ignored
+- * contrary to what firmware tells us.
++ /* The P2P Device interface event must not be ignored contrary to what
++ * firmware tells us. Older firmware uses p2p noif, with sta role.
++ * This should be accepted.
+ */
+- is_p2pdev = (ifevent->flags & BRCMF_E_IF_FLAG_NOIF) &&
+- ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT;
++ is_p2pdev = ((ifevent->flags & BRCMF_E_IF_FLAG_NOIF) &&
++ (ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT ||
++ ifevent->role == BRCMF_E_IF_ROLE_STA));
+ if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
+ brcmf_dbg(EVENT, "event can be ignored\n");
+ return;
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:15 +0200
+Subject: [PATCH] brcmfmac: Add module parameter to disable features.
+
+For debugging purpose it is very handy to be able to disable
+features. It has happened a few times that new features turned
+out not always being properly detected for all devices/firmwares.
+Making it possible to disable the feature with a module parameter
+will make testing/debugging easier.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/feature.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
+@@ -15,6 +15,7 @@
+ */
+
+ #include <linux/netdevice.h>
++#include <linux/module.h>
+
+ #include <brcm_hw_ids.h>
+ #include "core.h"
+@@ -23,6 +24,12 @@
+ #include "fwil.h"
+ #include "feature.h"
+
++
++/* Module param feature_disable (global for all devices) */
++static int brcmf_feature_disable;
++module_param_named(feature_disable, brcmf_feature_disable, int, 0);
++MODULE_PARM_DESC(feature_disable, "Disable features");
++
+ /*
+ * expand feature list to array of feature strings.
+ */
+@@ -131,6 +138,12 @@ void brcmf_feat_attach(struct brcmf_pub
+ brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_P2P, "p2p");
+
++ if (brcmf_feature_disable) {
++ brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
++ ifp->drvr->feat_flags, brcmf_feature_disable);
++ ifp->drvr->feat_flags &= ~brcmf_feature_disable;
++ }
++
+ /* set chip related quirks */
+ switch (drvr->bus_if->chip) {
+ case BRCM_CC_43236_CHIP_ID:
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:16 +0200
+Subject: [PATCH] brcmfmac: Fix race condition bug when deleting p2p interface.
+
+When p2p device interface gets deleted by deinitialising discovery
+it will result in an event which removes the interface, but that is
+also done by delete p2p interface code. This results in race
+condition which sometimes results in lockup/crash. With this patch
+the delete device interface will wait for the event (with timeout)
+removing the possible race condition. Also on the stop device call
+from cfg80211 the deinitialisation of the discovery device should
+be avoided as it can result in a similar situation.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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
+@@ -2238,6 +2238,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
+ brcmf_dbg(TRACE, "delete P2P vif\n");
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+
++ brcmf_cfg80211_arm_vif_event(cfg, vif);
+ switch (vif->wdev.iftype) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state))
+@@ -2254,8 +2255,6 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
+ return 0;
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+ brcmf_p2p_deinit_discovery(p2p);
+- brcmf_remove_interface(vif->ifp);
+- return 0;
+ default:
+ return -ENOTSUPP;
+ }
+@@ -2267,10 +2266,11 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
+ wait_for_completion_timeout(&cfg->vif_disabled,
+ msecs_to_jiffies(500));
+
+- brcmf_vif_clear_mgmt_ies(vif);
+-
+- brcmf_cfg80211_arm_vif_event(cfg, vif);
+- err = brcmf_p2p_release_p2p_if(vif);
++ err = 0;
++ if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE) {
++ brcmf_vif_clear_mgmt_ies(vif);
++ err = brcmf_p2p_release_p2p_if(vif);
++ }
+ if (!err) {
+ /* wait for firmware event */
+ err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL,
+@@ -2280,8 +2280,12 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
+ else
+ err = 0;
+ }
++ if (err)
++ brcmf_remove_interface(vif->ifp);
++
+ brcmf_cfg80211_arm_vif_event(cfg, NULL);
+- p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
++ if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE)
++ p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
+
+ return err;
+ }
+@@ -2330,7 +2334,9 @@ void brcmf_p2p_stop_device(struct wiphy
+ */
+ if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif == vif) {
+ mutex_lock(&cfg->usr_sync);
+- (void)brcmf_p2p_deinit_discovery(p2p);
++ /* Set the discovery state to SCAN */
++ (void)brcmf_p2p_set_discover_state(vif->ifp,
++ WL_P2P_DISC_ST_SCAN, 0, 0);
+ brcmf_abort_scanning(cfg);
+ clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
+ mutex_unlock(&cfg->usr_sync);
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:17 +0200
+Subject: [PATCH] brcmfmac: Add support for the BCM4365 and BCM4366 PCIE
+ devices.
+
+This patch adds support for the BCM4365 and BCM4366 11ac Wave2
+PCIE devices.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/chip.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
+@@ -208,6 +208,7 @@ struct sbsocramregs {
+ };
+
+ #define SOCRAMREGOFFS(_f) offsetof(struct sbsocramregs, _f)
++#define SYSMEMREGOFFS(_f) offsetof(struct sbsocramregs, _f)
+
+ #define ARMCR4_CAP (0x04)
+ #define ARMCR4_BANKIDX (0x40)
+@@ -516,6 +517,9 @@ static int brcmf_chip_cores_check(struct
+ case BCMA_CORE_ARM_CR4:
+ cpu_found = true;
+ break;
++ case BCMA_CORE_ARM_CA7:
++ cpu_found = true;
++ break;
+ default:
+ break;
+ }
+@@ -614,6 +618,29 @@ static void brcmf_chip_socram_ramsize(st
+ }
+ }
+
++/** Return the SYS MEM size */
++static u32 brcmf_chip_sysmem_ramsize(struct brcmf_core_priv *sysmem)
++{
++ u32 memsize = 0;
++ u32 coreinfo;
++ u32 idx;
++ u32 nb;
++ u32 banksize;
++
++ if (!brcmf_chip_iscoreup(&sysmem->pub))
++ brcmf_chip_resetcore(&sysmem->pub, 0, 0, 0);
++
++ coreinfo = brcmf_chip_core_read32(sysmem, SYSMEMREGOFFS(coreinfo));
++ nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
++
++ for (idx = 0; idx < nb; idx++) {
++ brcmf_chip_socram_banksize(sysmem, idx, &banksize);
++ memsize += banksize;
++ }
++
++ return memsize;
++}
++
+ /** Return the TCM-RAM size of the ARMCR4 core. */
+ static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4)
+ {
+@@ -656,6 +683,9 @@ static u32 brcmf_chip_tcm_rambase(struct
+ case BRCM_CC_4358_CHIP_ID:
+ case BRCM_CC_43602_CHIP_ID:
+ return 0x180000;
++ case BRCM_CC_4365_CHIP_ID:
++ case BRCM_CC_4366_CHIP_ID:
++ return 0x200000;
+ default:
+ brcmf_err("unknown chip: %s\n", ci->pub.name);
+ break;
+@@ -678,10 +708,28 @@ static int brcmf_chip_get_raminfo(struct
+ return -EINVAL;
+ }
+ } else {
+- mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_INTERNAL_MEM);
+- mem_core = container_of(mem, struct brcmf_core_priv, pub);
+- brcmf_chip_socram_ramsize(mem_core, &ci->pub.ramsize,
+- &ci->pub.srsize);
++ mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_SYS_MEM);
++ if (mem) {
++ mem_core = container_of(mem, struct brcmf_core_priv,
++ pub);
++ ci->pub.ramsize = brcmf_chip_sysmem_ramsize(mem_core);
++ ci->pub.rambase = brcmf_chip_tcm_rambase(ci);
++ if (!ci->pub.rambase) {
++ brcmf_err("RAM base not provided with ARM CA7 core\n");
++ return -EINVAL;
++ }
++ } else {
++ mem = brcmf_chip_get_core(&ci->pub,
++ BCMA_CORE_INTERNAL_MEM);
++ if (!mem) {
++ brcmf_err("No memory cores found\n");
++ return -ENOMEM;
++ }
++ mem_core = container_of(mem, struct brcmf_core_priv,
++ pub);
++ brcmf_chip_socram_ramsize(mem_core, &ci->pub.ramsize,
++ &ci->pub.srsize);
++ }
+ }
+ brcmf_dbg(INFO, "RAM: base=0x%x size=%d (0x%x) sr=%d (0x%x)\n",
+ ci->pub.rambase, ci->pub.ramsize, ci->pub.ramsize,
+@@ -924,7 +972,7 @@ static int brcmf_chip_recognition(struct
+ static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id)
+ {
+ struct brcmf_core *core;
+- struct brcmf_core_priv *cr4;
++ struct brcmf_core_priv *cpu;
+ u32 val;
+
+
+@@ -937,10 +985,11 @@ static void brcmf_chip_disable_arm(struc
+ brcmf_chip_coredisable(core, 0, 0);
+ break;
+ case BCMA_CORE_ARM_CR4:
+- cr4 = container_of(core, struct brcmf_core_priv, pub);
++ case BCMA_CORE_ARM_CA7:
++ cpu = container_of(core, struct brcmf_core_priv, pub);
+
+ /* clear all IOCTL bits except HALT bit */
+- val = chip->ops->read32(chip->ctx, cr4->wrapbase + BCMA_IOCTL);
++ val = chip->ops->read32(chip->ctx, cpu->wrapbase + BCMA_IOCTL);
+ val &= ARMCR4_BCMA_IOCTL_CPUHALT;
+ brcmf_chip_resetcore(core, val, ARMCR4_BCMA_IOCTL_CPUHALT,
+ ARMCR4_BCMA_IOCTL_CPUHALT);
+@@ -1162,6 +1211,33 @@ static bool brcmf_chip_cr4_set_active(st
+ return true;
+ }
+
++static inline void
++brcmf_chip_ca7_set_passive(struct brcmf_chip_priv *chip)
++{
++ struct brcmf_core *core;
++
++ brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CA7);
++
++ core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211);
++ brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET |
++ D11_BCMA_IOCTL_PHYCLOCKEN,
++ D11_BCMA_IOCTL_PHYCLOCKEN,
++ D11_BCMA_IOCTL_PHYCLOCKEN);
++}
++
++static bool brcmf_chip_ca7_set_active(struct brcmf_chip_priv *chip, u32 rstvec)
++{
++ struct brcmf_core *core;
++
++ chip->ops->activate(chip->ctx, &chip->pub, rstvec);
++
++ /* restore ARM */
++ core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CA7);
++ brcmf_chip_resetcore(core, ARMCR4_BCMA_IOCTL_CPUHALT, 0, 0);
++
++ return true;
++}
++
+ void brcmf_chip_set_passive(struct brcmf_chip *pub)
+ {
+ struct brcmf_chip_priv *chip;
+@@ -1175,8 +1251,16 @@ void brcmf_chip_set_passive(struct brcmf
+ brcmf_chip_cr4_set_passive(chip);
+ return;
+ }
+-
+- brcmf_chip_cm3_set_passive(chip);
++ arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CA7);
++ if (arm) {
++ brcmf_chip_ca7_set_passive(chip);
++ return;
++ }
++ arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CM3);
++ if (arm) {
++ brcmf_chip_cm3_set_passive(chip);
++ return;
++ }
+ }
+
+ bool brcmf_chip_set_active(struct brcmf_chip *pub, u32 rstvec)
+@@ -1190,8 +1274,14 @@ bool brcmf_chip_set_active(struct brcmf_
+ arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4);
+ if (arm)
+ return brcmf_chip_cr4_set_active(chip, rstvec);
++ arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CA7);
++ if (arm)
++ return brcmf_chip_ca7_set_active(chip, rstvec);
++ arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CM3);
++ if (arm)
++ return brcmf_chip_cm3_set_active(chip);
+
+- return brcmf_chip_cm3_set_active(chip);
++ return false;
+ }
+
+ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
+--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+@@ -55,6 +55,10 @@ enum brcmf_pcie_state {
+ #define BRCMF_PCIE_43570_NVRAM_NAME "brcm/brcmfmac43570-pcie.txt"
+ #define BRCMF_PCIE_4358_FW_NAME "brcm/brcmfmac4358-pcie.bin"
+ #define BRCMF_PCIE_4358_NVRAM_NAME "brcm/brcmfmac4358-pcie.txt"
++#define BRCMF_PCIE_4365_FW_NAME "brcm/brcmfmac4365b-pcie.bin"
++#define BRCMF_PCIE_4365_NVRAM_NAME "brcm/brcmfmac4365b-pcie.txt"
++#define BRCMF_PCIE_4366_FW_NAME "brcm/brcmfmac4366b-pcie.bin"
++#define BRCMF_PCIE_4366_NVRAM_NAME "brcm/brcmfmac4366b-pcie.txt"
+
+ #define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */
+
+@@ -204,6 +208,10 @@ MODULE_FIRMWARE(BRCMF_PCIE_43570_FW_NAME
+ MODULE_FIRMWARE(BRCMF_PCIE_43570_NVRAM_NAME);
+ MODULE_FIRMWARE(BRCMF_PCIE_4358_FW_NAME);
+ MODULE_FIRMWARE(BRCMF_PCIE_4358_NVRAM_NAME);
++MODULE_FIRMWARE(BRCMF_PCIE_4365_FW_NAME);
++MODULE_FIRMWARE(BRCMF_PCIE_4365_NVRAM_NAME);
++MODULE_FIRMWARE(BRCMF_PCIE_4366_FW_NAME);
++MODULE_FIRMWARE(BRCMF_PCIE_4366_NVRAM_NAME);
+
+
+ struct brcmf_pcie_console {
+@@ -1440,6 +1448,14 @@ static int brcmf_pcie_get_fwnames(struct
+ fw_name = BRCMF_PCIE_4358_FW_NAME;
+ nvram_name = BRCMF_PCIE_4358_NVRAM_NAME;
+ break;
++ case BRCM_CC_4365_CHIP_ID:
++ fw_name = BRCMF_PCIE_4365_FW_NAME;
++ nvram_name = BRCMF_PCIE_4365_NVRAM_NAME;
++ break;
++ case BRCM_CC_4366_CHIP_ID:
++ fw_name = BRCMF_PCIE_4366_FW_NAME;
++ nvram_name = BRCMF_PCIE_4366_NVRAM_NAME;
++ break;
+ default:
+ brcmf_err("Unsupported chip 0x%04x\n", devinfo->ci->chip);
+ return -ENODEV;
+@@ -1973,6 +1989,12 @@ static struct pci_device_id brcmf_pcie_d
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_RAW_DEVICE_ID),
++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID),
++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID),
++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID),
++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID),
++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID),
++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID),
+ { /* end: all zeroes */ }
+ };
+
+--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
++++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
+@@ -48,6 +48,8 @@
+ #define BRCM_CC_43570_CHIP_ID 43570
+ #define BRCM_CC_4358_CHIP_ID 0x4358
+ #define BRCM_CC_43602_CHIP_ID 43602
++#define BRCM_CC_4365_CHIP_ID 0x4365
++#define BRCM_CC_4366_CHIP_ID 0x4366
+
+ /* USB Device IDs */
+ #define BRCM_USB_43143_DEVICE_ID 0xbd1e
+@@ -67,6 +69,13 @@
+ #define BRCM_PCIE_43602_2G_DEVICE_ID 0x43bb
+ #define BRCM_PCIE_43602_5G_DEVICE_ID 0x43bc
+ #define BRCM_PCIE_43602_RAW_DEVICE_ID 43602
++#define BRCM_PCIE_4365_DEVICE_ID 0x43ca
++#define BRCM_PCIE_4365_2G_DEVICE_ID 0x43cb
++#define BRCM_PCIE_4365_5G_DEVICE_ID 0x43cc
++#define BRCM_PCIE_4366_DEVICE_ID 0x43c3
++#define BRCM_PCIE_4366_2G_DEVICE_ID 0x43c4
++#define BRCM_PCIE_4366_5G_DEVICE_ID 0x43c5
++
+
+ /* brcmsmac IDs */
+ #define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:18 +0200
+Subject: [PATCH] brcmfmac: Fix TDLS setup by properly handling p2p noif.
+
+There is a workaround needed for p2p device setup which breaks tdls
+functionality. This patch fixes that by properly signalling fweh that
+p2p device setup is ongoing.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/fweh.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+@@ -188,11 +188,13 @@ static void brcmf_fweh_handle_if_event(s
+
+ /* The P2P Device interface event must not be ignored contrary to what
+ * firmware tells us. Older firmware uses p2p noif, with sta role.
+- * This should be accepted.
++ * This should be accepted when p2pdev_setup is ongoing. TDLS setup will
++ * use the same ifevent and should be ignored.
+ */
+ is_p2pdev = ((ifevent->flags & BRCMF_E_IF_FLAG_NOIF) &&
+ (ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT ||
+- ifevent->role == BRCMF_E_IF_ROLE_STA));
++ ((ifevent->role == BRCMF_E_IF_ROLE_STA) &&
++ (drvr->fweh.p2pdev_setup_ongoing))));
+ if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
+ brcmf_dbg(EVENT, "event can be ignored\n");
+ return;
+@@ -316,6 +318,17 @@ event_free:
+ }
+
+ /**
++ * brcmf_fweh_p2pdev_setup() - P2P device setup ongoing (or not).
++ *
++ * @ifp: ifp on which setup is taking place or finished.
++ * @ongoing: p2p device setup in progress (or not).
++ */
++void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing)
++{
++ ifp->drvr->fweh.p2pdev_setup_ongoing = ongoing;
++}
++
++/**
+ * brcmf_fweh_attach() - initialize firmware event handling.
+ *
+ * @drvr: driver information object.
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
+@@ -230,12 +230,14 @@ typedef int (*brcmf_fweh_handler_t)(stru
+ /**
+ * struct brcmf_fweh_info - firmware event handling information.
+ *
++ * @p2pdev_setup_ongoing: P2P device creation in progress.
+ * @event_work: event worker.
+ * @evt_q_lock: lock for event queue protection.
+ * @event_q: event queue.
+ * @evt_handler: registered event handlers.
+ */
+ struct brcmf_fweh_info {
++ bool p2pdev_setup_ongoing;
+ struct work_struct event_work;
+ spinlock_t evt_q_lock;
+ struct list_head event_q;
+@@ -255,6 +257,7 @@ void brcmf_fweh_unregister(struct brcmf_
+ int brcmf_fweh_activate_events(struct brcmf_if *ifp);
+ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
+ struct brcmf_event *event_packet);
++void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
+
+ static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
+ struct sk_buff *skb)
+--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+@@ -2084,11 +2084,13 @@ static struct wireless_dev *brcmf_p2p_cr
+ brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
+
+ brcmf_cfg80211_arm_vif_event(p2p->cfg, p2p_vif);
++ brcmf_fweh_p2pdev_setup(pri_ifp, true);
+
+ /* 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_fweh_p2pdev_setup(pri_ifp, false);
+ brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
+ goto fail;
+ }
+@@ -2097,6 +2099,7 @@ static struct wireless_dev *brcmf_p2p_cr
+ err = brcmf_cfg80211_wait_vif_event_timeout(p2p->cfg, BRCMF_E_IF_ADD,
+ msecs_to_jiffies(1500));
+ brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
++ brcmf_fweh_p2pdev_setup(pri_ifp, false);
+ if (!err) {
+ brcmf_err("timeout occurred\n");
+ err = -EIO;
+@@ -2393,6 +2396,8 @@ s32 brcmf_p2p_attach(struct brcmf_cfg802
+ memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+ brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
+
++ brcmf_fweh_p2pdev_setup(pri_ifp, true);
++
+ /* Initialize P2P Discovery in the firmware */
+ err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
+ if (err < 0) {
+@@ -2419,8 +2424,9 @@ s32 brcmf_p2p_attach(struct brcmf_cfg802
+ 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:
++ brcmf_fweh_p2pdev_setup(pri_ifp, false);
++ }
+ return err;
+ }
+
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:19 +0200
+Subject: [PATCH] brcmfmac: Accept events when TDLS is used in combination with
+ p2p.
+
+TDLS events are mapped back to primary interface but when p2p is in
+use then this fails because the check was incorrect by checking
+bsscfg number. Which can be different when a p2p device has been
+created.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-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/fweh.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+@@ -300,8 +300,7 @@ static void brcmf_fweh_event_worker(stru
+ goto event_free;
+ }
+
+- if ((event->code == BRCMF_E_TDLS_PEER_EVENT) &&
+- (emsg.bsscfgidx == 1))
++ if (event->code == BRCMF_E_TDLS_PEER_EVENT)
+ ifp = drvr->iflist[0];
+ else
+ ifp = drvr->iflist[emsg.bsscfgidx];
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
-@@ -1213,6 +1213,7 @@ static int __init brcmfmac_module_init(v
+@@ -1229,6 +1229,7 @@ static int __init brcmfmac_module_init(v
#endif
if (!schedule_work(&brcmf_driver_work))
return -EBUSY;
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-@@ -691,9 +691,37 @@ static struct wireless_dev *brcmf_cfg802
+@@ -608,9 +608,37 @@ static struct wireless_dev *brcmf_cfg802
u32 *flags,
struct vif_params *params)
{