--- /dev/null
+From 1b8d2e0a9e4221b99eea375c079507ce8ef655f5 Mon Sep 17 00:00:00 2001
+From: Wright Feng <wright.feng@cypress.com>
+Date: Thu, 12 Dec 2019 00:52:45 +0100
+Subject: [PATCH 1/7] brcmfmac: reset two D11 cores if chip has two D11 cores
+
+There are two D11 cores in RSDB chips like 4359. We have to reset two
+D11 cores simutaneously before firmware download, or the firmware may
+not be initialized correctly and cause "fw initialized failed" error.
+
+Signed-off-by: Wright Feng <wright.feng@cypress.com>
+Signed-off-by: Soeren Moch <smoch@web.de>
+Reviewed-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../broadcom/brcm80211/brcmfmac/chip.c | 50 +++++++++++++++++++
+ .../broadcom/brcm80211/brcmfmac/chip.h | 1 +
+ .../broadcom/brcm80211/brcmfmac/pcie.c | 2 +-
+ 3 files changed, 52 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+@@ -433,11 +433,25 @@ static void brcmf_chip_ai_resetcore(stru
+ {
+ struct brcmf_chip_priv *ci;
+ int count;
++ struct brcmf_core *d11core2 = NULL;
++ struct brcmf_core_priv *d11priv2 = NULL;
+
+ ci = core->chip;
+
++ /* special handle two D11 cores reset */
++ if (core->pub.id == BCMA_CORE_80211) {
++ d11core2 = brcmf_chip_get_d11core(&ci->pub, 1);
++ if (d11core2) {
++ brcmf_dbg(INFO, "found two d11 cores, reset both\n");
++ d11priv2 = container_of(d11core2,
++ struct brcmf_core_priv, pub);
++ }
++ }
++
+ /* must disable first to work for arbitrary current core state */
+ brcmf_chip_ai_coredisable(core, prereset, reset);
++ if (d11priv2)
++ brcmf_chip_ai_coredisable(d11priv2, prereset, reset);
+
+ count = 0;
+ while (ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) &
+@@ -449,9 +463,30 @@ static void brcmf_chip_ai_resetcore(stru
+ usleep_range(40, 60);
+ }
+
++ if (d11priv2) {
++ count = 0;
++ while (ci->ops->read32(ci->ctx,
++ d11priv2->wrapbase + BCMA_RESET_CTL) &
++ BCMA_RESET_CTL_RESET) {
++ ci->ops->write32(ci->ctx,
++ d11priv2->wrapbase + BCMA_RESET_CTL,
++ 0);
++ count++;
++ if (count > 50)
++ break;
++ usleep_range(40, 60);
++ }
++ }
++
+ ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
+ postreset | BCMA_IOCTL_CLK);
+ ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
++
++ if (d11priv2) {
++ ci->ops->write32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL,
++ postreset | BCMA_IOCTL_CLK);
++ ci->ops->read32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL);
++ }
+ }
+
+ char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len)
+@@ -1109,6 +1144,21 @@ void brcmf_chip_detach(struct brcmf_chip
+ kfree(chip);
+ }
+
++struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit)
++{
++ struct brcmf_chip_priv *chip;
++ struct brcmf_core_priv *core;
++
++ chip = container_of(pub, struct brcmf_chip_priv, pub);
++ list_for_each_entry(core, &chip->cores, list) {
++ if (core->pub.id == BCMA_CORE_80211) {
++ if (unit-- == 0)
++ return &core->pub;
++ }
++ }
++ return NULL;
++}
++
+ struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *pub, u16 coreid)
+ {
+ struct brcmf_chip_priv *chip;
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
+@@ -74,6 +74,7 @@ struct brcmf_chip *brcmf_chip_attach(voi
+ const struct brcmf_buscore_ops *ops);
+ void brcmf_chip_detach(struct brcmf_chip *chip);
+ struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid);
++struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit);
+ struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip);
+ struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub);
+ bool brcmf_chip_iscoreup(struct brcmf_core *core);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+@@ -78,7 +78,7 @@ static const struct brcmf_firmware_mappi
+ BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
+ };
+
+-#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */
++#define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */
+
+ #define BRCMF_PCIE_REG_MAP_SIZE (32 * 1024)
+
--- /dev/null
+From 172f6854551d48d1c9530f84513b421db944e714 Mon Sep 17 00:00:00 2001
+From: Chung-Hsien Hsu <stanley.hsu@cypress.com>
+Date: Thu, 12 Dec 2019 00:52:46 +0100
+Subject: [PATCH 2/7] brcmfmac: set F2 blocksize and watermark for 4359
+
+Set F2 blocksize to 256 bytes and watermark to 0x40 for 4359. Also
+enable and configure F1 MesBusyCtrl. It fixes DMA error while having
+UDP bi-directional traffic.
+
+Signed-off-by: Chung-Hsien Hsu <stanley.hsu@cypress.com>
+[slightly adapted for rebase on mainline linux]
+Signed-off-by: Soeren Moch <smoch@web.de>
+Reviewed-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 +++++-
+ .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 15 +++++++++++++++
+ 2 files changed, 20 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+@@ -43,6 +43,7 @@
+
+ #define SDIO_FUNC1_BLOCKSIZE 64
+ #define SDIO_FUNC2_BLOCKSIZE 512
++#define SDIO_4359_FUNC2_BLOCKSIZE 256
+ /* Maximum milliseconds to wait for F2 to come up */
+ #define SDIO_WAIT_F2RDY 3000
+
+@@ -892,6 +893,7 @@ static void brcmf_sdiod_host_fixup(struc
+ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
+ {
+ int ret = 0;
++ unsigned int f2_blksz = SDIO_FUNC2_BLOCKSIZE;
+
+ sdio_claim_host(sdiodev->func1);
+
+@@ -901,7 +903,9 @@ static int brcmf_sdiod_probe(struct brcm
+ sdio_release_host(sdiodev->func1);
+ goto out;
+ }
+- ret = sdio_set_block_size(sdiodev->func2, SDIO_FUNC2_BLOCKSIZE);
++ if (sdiodev->func2->device == SDIO_DEVICE_ID_BROADCOM_4359)
++ f2_blksz = SDIO_4359_FUNC2_BLOCKSIZE;
++ ret = sdio_set_block_size(sdiodev->func2, f2_blksz);
+ if (ret) {
+ brcmf_err("Failed to set F2 blocksize\n");
+ sdio_release_host(sdiodev->func1);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+@@ -42,6 +42,8 @@
+ #define DEFAULT_F2_WATERMARK 0x8
+ #define CY_4373_F2_WATERMARK 0x40
+ #define CY_43012_F2_WATERMARK 0x60
++#define CY_4359_F2_WATERMARK 0x40
++#define CY_4359_F1_MESBUSYCTRL (CY_4359_F2_WATERMARK | SBSDIO_MESBUSYCTRL_ENAB)
+
+ #ifdef DEBUG
+
+@@ -4210,6 +4212,19 @@ static void brcmf_sdio_firmware_callback
+ brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl,
+ &err);
+ break;
++ case SDIO_DEVICE_ID_BROADCOM_4359:
++ brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n",
++ CY_4359_F2_WATERMARK);
++ brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK,
++ CY_4359_F2_WATERMARK, &err);
++ devctl = brcmf_sdiod_readb(sdiod, SBSDIO_DEVICE_CTL,
++ &err);
++ devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
++ brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl,
++ &err);
++ brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL,
++ CY_4359_F1_MESBUSYCTRL, &err);
++ break;
+ default:
+ brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK,
+ DEFAULT_F2_WATERMARK, &err);
--- /dev/null
+From 6647274ed995a172369cb04754eb5f8b85f68f6d Mon Sep 17 00:00:00 2001
+From: Soeren Moch <smoch@web.de>
+Date: Thu, 12 Dec 2019 00:52:47 +0100
+Subject: [PATCH 3/7] brcmfmac: fix rambase for 4359/9
+
+Newer 4359 chip revisions need a different rambase address.
+This fixes firmware download on such devices which fails otherwise.
+
+Signed-off-by: Soeren Moch <smoch@web.de>
+Acked-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+@@ -712,7 +712,6 @@ static u32 brcmf_chip_tcm_rambase(struct
+ case BRCM_CC_43569_CHIP_ID:
+ case BRCM_CC_43570_CHIP_ID:
+ case BRCM_CC_4358_CHIP_ID:
+- case BRCM_CC_4359_CHIP_ID:
+ case BRCM_CC_43602_CHIP_ID:
+ case BRCM_CC_4371_CHIP_ID:
+ return 0x180000;
+@@ -722,6 +721,8 @@ static u32 brcmf_chip_tcm_rambase(struct
+ case BRCM_CC_4366_CHIP_ID:
+ case BRCM_CC_43664_CHIP_ID:
+ return 0x200000;
++ case BRCM_CC_4359_CHIP_ID:
++ return (ci->pub.chiprev < 9) ? 0x180000 : 0x160000;
+ case CY_CC_4373_CHIP_ID:
+ return 0x160000;
+ default:
--- /dev/null
+From c12c8913d79c49ceccb38f42714d25b783833758 Mon Sep 17 00:00:00 2001
+From: Soeren Moch <smoch@web.de>
+Date: Thu, 12 Dec 2019 00:52:48 +0100
+Subject: [PATCH 4/7] brcmfmac: make errors when setting roaming parameters
+ non-fatal
+
+4359 dongles do not support setting roaming parameters (error -52).
+Do not fail the 80211 configuration in this case.
+
+Signed-off-by: Soeren Moch <smoch@web.de>
+Acked-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -5936,19 +5936,17 @@ static s32 brcmf_dongle_roam(struct brcm
+ roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
+ (void *)roamtrigger, sizeof(roamtrigger));
+- if (err) {
++ if (err)
+ bphy_err(drvr, "WLC_SET_ROAM_TRIGGER error (%d)\n", err);
+- goto roam_setup_done;
+- }
+
+ roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
+ roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
+ (void *)roam_delta, sizeof(roam_delta));
+- if (err) {
++ if (err)
+ bphy_err(drvr, "WLC_SET_ROAM_DELTA error (%d)\n", err);
+- goto roam_setup_done;
+- }
++
++ return 0;
+
+ roam_setup_done:
+ return err;
--- /dev/null
+From d4aef159394d5940bd7158ab789969dab82f7c76 Mon Sep 17 00:00:00 2001
+From: Soeren Moch <smoch@web.de>
+Date: Thu, 12 Dec 2019 00:52:49 +0100
+Subject: [PATCH 5/7] brcmfmac: add support for BCM4359 SDIO chipset
+
+BCM4359 is a 2x2 802.11 abgn+ac Dual-Band HT80 combo chip and it
+supports Real Simultaneous Dual Band feature.
+
+Based on a similar patch by: Wright Feng <wright.feng@cypress.com>
+
+Signed-off-by: Soeren Moch <smoch@web.de>
+Acked-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
+Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 2 ++
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 1 +
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 ++
+ include/linux/mmc/sdio_ids.h | 2 ++
+ 4 files changed, 7 insertions(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+@@ -962,8 +962,10 @@ static const struct sdio_device_id brcmf
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356),
++ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_4373),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_43012),
++ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_89359),
+ { /* end: all zeroes */ }
+ };
+ MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+@@ -1408,6 +1408,7 @@ bool brcmf_chip_sr_capable(struct brcmf_
+ addr = CORE_CC_REG(base, sr_control0);
+ reg = chip->ops->read32(chip->ctx, addr);
+ return (reg & CC_SR_CTL0_ENABLE_MASK) != 0;
++ case BRCM_CC_4359_CHIP_ID:
+ case CY_CC_43012_CHIP_ID:
+ addr = CORE_CC_REG(pmu->base, retention_ctl);
+ reg = chip->ops->read32(chip->ctx, addr);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+@@ -616,6 +616,7 @@ BRCMF_FW_DEF(43455, "brcmfmac43455-sdio"
+ BRCMF_FW_DEF(43456, "brcmfmac43456-sdio");
+ BRCMF_FW_DEF(4354, "brcmfmac4354-sdio");
+ BRCMF_FW_DEF(4356, "brcmfmac4356-sdio");
++BRCMF_FW_DEF(4359, "brcmfmac4359-sdio");
+ BRCMF_FW_DEF(4373, "brcmfmac4373-sdio");
+ BRCMF_FW_DEF(43012, "brcmfmac43012-sdio");
+
+@@ -638,6 +639,7 @@ static const struct brcmf_firmware_mappi
+ BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455),
+ BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
+ BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
++ BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
+ BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373),
+ BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012)
+ };
+--- a/include/linux/mmc/sdio_ids.h
++++ b/include/linux/mmc/sdio_ids.h
+@@ -41,8 +41,10 @@
+ #define SDIO_DEVICE_ID_BROADCOM_43455 0xa9bf
+ #define SDIO_DEVICE_ID_BROADCOM_4354 0x4354
+ #define SDIO_DEVICE_ID_BROADCOM_4356 0x4356
++#define SDIO_DEVICE_ID_BROADCOM_4359 0x4359
+ #define SDIO_DEVICE_ID_CYPRESS_4373 0x4373
+ #define SDIO_DEVICE_ID_CYPRESS_43012 43012
++#define SDIO_DEVICE_ID_CYPRESS_89359 0x4355
+
+ #define SDIO_VENDOR_ID_INTEL 0x0089
+ #define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402
--- /dev/null
+From 837482e69a3f0d7cbc73922020012f83635f5ddb Mon Sep 17 00:00:00 2001
+From: Wright Feng <wright.feng@cypress.com>
+Date: Thu, 12 Dec 2019 00:52:50 +0100
+Subject: [PATCH 6/7] brcmfmac: add RSDB condition when setting interface
+ combinations
+
+With firmware RSDB feature
+1. The maximum support interface is four.
+2. The maximum difference channel is two.
+3. The maximum interfaces of {station/p2p client/AP} are two.
+4. The maximum interface of p2p device is one.
+
+Signed-off-by: Wright Feng <wright.feng@cypress.com>
+Signed-off-by: Soeren Moch <smoch@web.de>
+Reviewed-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../broadcom/brcm80211/brcmfmac/cfg80211.c | 54 ++++++++++++++++---
+ 1 file changed, 46 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -6444,6 +6444,9 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
+ * #STA <= 1, #AP <= 1, channels = 1, 2 total
+ * #AP <= 4, matching BI, channels = 1, 4 total
+ *
++ * no p2p and rsdb:
++ * #STA <= 2, #AP <= 2, channels = 2, 4 total
++ *
+ * p2p, no mchan, and mbss:
+ *
+ * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
+@@ -6455,6 +6458,10 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
+ * #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
++ *
++ * p2p, rsdb, and no mbss:
++ * #STA <= 2, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 2, AP <= 2,
++ * channels = 2, 4 total
+ */
+ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
+ {
+@@ -6462,13 +6469,14 @@ static int brcmf_setup_ifmodes(struct wi
+ struct ieee80211_iface_limit *c0_limits = NULL;
+ struct ieee80211_iface_limit *p2p_limits = NULL;
+ struct ieee80211_iface_limit *mbss_limits = NULL;
+- bool mbss, p2p;
++ bool mbss, p2p, rsdb;
+ int i, c, n_combos;
+
+ mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
+ p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
++ rsdb = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB);
+
+- n_combos = 1 + !!p2p + !!mbss;
++ n_combos = 1 + !!(p2p && !rsdb) + !!mbss;
+ combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
+ if (!combo)
+ goto err;
+@@ -6479,16 +6487,36 @@ static int brcmf_setup_ifmodes(struct wi
+
+ c = 0;
+ i = 0;
+- c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
++ if (p2p && rsdb)
++ c0_limits = kcalloc(4, sizeof(*c0_limits), GFP_KERNEL);
++ else if (p2p)
++ c0_limits = kcalloc(3, sizeof(*c0_limits), GFP_KERNEL);
++ else
++ c0_limits = kcalloc(2, sizeof(*c0_limits), GFP_KERNEL);
+ if (!c0_limits)
+ goto err;
+- c0_limits[i].max = 1;
+- c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+- if (p2p) {
++ if (p2p && rsdb) {
++ combo[c].num_different_channels = 2;
++ wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
++ BIT(NL80211_IFTYPE_P2P_GO) |
++ BIT(NL80211_IFTYPE_P2P_DEVICE);
++ c0_limits[i].max = 2;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++ c0_limits[i].max = 1;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
++ c0_limits[i].max = 2;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
++ BIT(NL80211_IFTYPE_P2P_GO);
++ c0_limits[i].max = 2;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
++ combo[c].max_interfaces = 5;
++ } else if (p2p) {
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
+ combo[c].num_different_channels = 2;
+ else
+ combo[c].num_different_channels = 1;
++ c0_limits[i].max = 1;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
+@@ -6497,16 +6525,26 @@ static int brcmf_setup_ifmodes(struct wi
+ c0_limits[i].max = 1;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO);
++ combo[c].max_interfaces = i;
++ } else if (rsdb) {
++ combo[c].num_different_channels = 2;
++ c0_limits[i].max = 2;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++ c0_limits[i].max = 2;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
++ combo[c].max_interfaces = 3;
+ } else {
+ combo[c].num_different_channels = 1;
+ c0_limits[i].max = 1;
++ c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
++ c0_limits[i].max = 1;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
++ combo[c].max_interfaces = i;
+ }
+- combo[c].max_interfaces = i;
+ combo[c].n_limits = i;
+ combo[c].limits = c0_limits;
+
+- if (p2p) {
++ if (p2p && !rsdb) {
+ c++;
+ i = 0;
+ p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
--- /dev/null
+From 2635853ce4ab7654a77ab7080fb56de83408606b Mon Sep 17 00:00:00 2001
+From: Wright Feng <wright.feng@cypress.com>
+Date: Thu, 12 Dec 2019 00:52:51 +0100
+Subject: [PATCH 7/7] brcmfmac: not set mbss in vif if firmware does not
+ support MBSS
+
+With RSDB mode, FMAC and firmware are able to create 2 or more AP,
+so we should not set mbss in vif structure if firmware does not
+support MBSS feature.
+
+Signed-off-by: Wright Feng <wright.feng@cypress.com>
+Signed-off-by: Soeren Moch <smoch@web.de>
+Reviewed-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -5293,6 +5293,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_v
+ struct brcmf_cfg80211_vif *vif_walk;
+ struct brcmf_cfg80211_vif *vif;
+ bool mbss;
++ struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
+
+ brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
+ sizeof(*vif));
+@@ -5305,7 +5306,8 @@ struct brcmf_cfg80211_vif *brcmf_alloc_v
+
+ brcmf_init_prof(&vif->profile);
+
+- if (type == NL80211_IFTYPE_AP) {
++ if (type == NL80211_IFTYPE_AP &&
++ brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
+ mbss = false;
+ list_for_each_entry(vif_walk, &cfg->vif_list, list) {
+ if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {