From: Rafał Miłecki Date: Fri, 24 Apr 2015 10:53:11 +0000 (+0000) Subject: mac80211: backport brcmfmac to support multiple devices NVRAM X-Git-Tag: reboot~3165 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=84a3e668fc852afea25aadf8ee6f04a661fae280;p=openwrt%2Fstaging%2Fnoltari.git mac80211: backport brcmfmac to support multiple devices NVRAM Signed-off-by: Rafał Miłecki SVN-Revision: 45577 --- diff --git a/package/kernel/mac80211/patches/354-brcmfmac-use-static-superset-of-channels-for-wiphy-b.patch b/package/kernel/mac80211/patches/354-brcmfmac-use-static-superset-of-channels-for-wiphy-b.patch new file mode 100644 index 0000000000..6e461f617f --- /dev/null +++ b/package/kernel/mac80211/patches/354-brcmfmac-use-static-superset-of-channels-for-wiphy-b.patch @@ -0,0 +1,300 @@ +From: Arend van Spriel +Date: Tue, 14 Apr 2015 20:10:24 +0200 +Subject: [PATCH] brcmfmac: use static superset of channels for wiphy + bands + +The driver was constructing a list of channels per wiphy band +by querying the device. This list is not what the hardware is +able to do as it is already filtered by the country setting in +the device. As user-space may change the country this would +require updating the channel list which is not recommended [1]. +This patch introduces a superset of channels. The individual +channels are disabled appropriately by querying the device. + +[1] http://mid.gmane.org/1426706320.3001.21.camel@sipsolutions.net + +Reviewed-by: Hante Meuleman +Reviewed-by: Daniel (Deognyoun) Kim +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -129,13 +129,47 @@ static struct ieee80211_rate __wl_rates[ + RATETAB_ENT(BRCM_RATE_54M, 0), + }; + +-#define wl_a_rates (__wl_rates + 4) +-#define wl_a_rates_size 8 + #define wl_g_rates (__wl_rates + 0) +-#define wl_g_rates_size 12 ++#define wl_g_rates_size ARRAY_SIZE(__wl_rates) ++#define wl_a_rates (__wl_rates + 4) ++#define wl_a_rates_size (wl_g_rates_size - 4) ++ ++#define CHAN2G(_channel, _freq) { \ ++ .band = IEEE80211_BAND_2GHZ, \ ++ .center_freq = (_freq), \ ++ .hw_value = (_channel), \ ++ .flags = IEEE80211_CHAN_DISABLED, \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++#define CHAN5G(_channel) { \ ++ .band = IEEE80211_BAND_5GHZ, \ ++ .center_freq = 5000 + (5 * (_channel)), \ ++ .hw_value = (_channel), \ ++ .flags = IEEE80211_CHAN_DISABLED, \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++static struct ieee80211_channel __wl_2ghz_channels[] = { ++ CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427), ++ CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447), ++ CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467), ++ CHAN2G(13, 2472), CHAN2G(14, 2484) ++}; ++ ++static struct ieee80211_channel __wl_5ghz_channels[] = { ++ CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42), ++ CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56), ++ CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108), ++ CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128), ++ CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149), ++ CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165) ++}; + + /* Band templates duplicated per wiphy. The channel info +- * is filled in after querying the device. ++ * above is added to the band during setup. + */ + static const struct ieee80211_supported_band __wl_band_2ghz = { + .band = IEEE80211_BAND_2GHZ, +@@ -143,7 +177,7 @@ static const struct ieee80211_supported_ + .n_bitrates = wl_g_rates_size, + }; + +-static const struct ieee80211_supported_band __wl_band_5ghz_a = { ++static const struct ieee80211_supported_band __wl_band_5ghz = { + .band = IEEE80211_BAND_5GHZ, + .bitrates = wl_a_rates, + .n_bitrates = wl_a_rates_size, +@@ -5252,40 +5286,6 @@ dongle_scantime_out: + return err; + } + +-/* Filter the list of channels received from firmware counting only +- * the 20MHz channels. The wiphy band data only needs those which get +- * flagged to indicate if they can take part in higher bandwidth. +- */ +-static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg, +- struct brcmf_chanspec_list *chlist, +- u32 chcnt[]) +-{ +- u32 total = le32_to_cpu(chlist->count); +- struct brcmu_chan ch; +- int i; +- +- for (i = 0; i < total; i++) { +- ch.chspec = (u16)le32_to_cpu(chlist->element[i]); +- cfg->d11inf.decchspec(&ch); +- +- /* Firmware gives a ordered list. We skip non-20MHz +- * channels is 2G. For 5G we can abort upon reaching +- * a non-20MHz channel in the list. +- */ +- if (ch.bw != BRCMU_CHAN_BW_20) { +- if (ch.band == BRCMU_CHAN_BAND_5G) +- break; +- else +- continue; +- } +- +- if (ch.band == BRCMU_CHAN_BAND_2G) +- chcnt[0] += 1; +- else if (ch.band == BRCMU_CHAN_BAND_5G) +- chcnt[1] += 1; +- } +-} +- + static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel, + struct brcmu_chan *ch) + { +@@ -5321,7 +5321,6 @@ static int brcmf_construct_chaninfo(stru + u32 i, j; + u32 total; + u32 chaninfo; +- u32 chcnt[2] = { 0, 0 }; + u32 index; + + pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL); +@@ -5338,42 +5337,15 @@ static int brcmf_construct_chaninfo(stru + goto fail_pbuf; + } + +- brcmf_count_20mhz_channels(cfg, list, chcnt); + wiphy = cfg_to_wiphy(cfg); +- if (chcnt[0]) { +- band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz), +- GFP_KERNEL); +- if (band == NULL) { +- err = -ENOMEM; +- goto fail_pbuf; +- } +- band->channels = kcalloc(chcnt[0], sizeof(*channel), +- GFP_KERNEL); +- if (band->channels == NULL) { +- kfree(band); +- err = -ENOMEM; +- goto fail_pbuf; +- } +- band->n_channels = 0; +- wiphy->bands[IEEE80211_BAND_2GHZ] = band; +- } +- if (chcnt[1]) { +- band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a), +- GFP_KERNEL); +- if (band == NULL) { +- err = -ENOMEM; +- goto fail_band2g; +- } +- band->channels = kcalloc(chcnt[1], sizeof(*channel), +- GFP_KERNEL); +- if (band->channels == NULL) { +- kfree(band); +- err = -ENOMEM; +- goto fail_band2g; +- } +- band->n_channels = 0; +- wiphy->bands[IEEE80211_BAND_5GHZ] = band; +- } ++ band = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ if (band) ++ for (i = 0; i < band->n_channels; i++) ++ band->channels[i].flags = IEEE80211_CHAN_DISABLED; ++ band = wiphy->bands[IEEE80211_BAND_5GHZ]; ++ if (band) ++ for (i = 0; i < band->n_channels; i++) ++ band->channels[i].flags = IEEE80211_CHAN_DISABLED; + + total = le32_to_cpu(list->count); + for (i = 0; i < total; i++) { +@@ -5388,6 +5360,8 @@ static int brcmf_construct_chaninfo(stru + brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec); + continue; + } ++ if (!band) ++ continue; + if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) && + ch.bw == BRCMU_CHAN_BW_40) + continue; +@@ -5415,9 +5389,9 @@ static int brcmf_construct_chaninfo(stru + } else if (ch.bw == BRCMU_CHAN_BW_40) { + brcmf_update_bw40_channel_flag(&channel[index], &ch); + } else { +- /* disable other bandwidths for now as mentioned +- * order assure they are enabled for subsequent +- * chanspecs. ++ /* enable the channel and disable other bandwidths ++ * for now as mentioned order assure they are enabled ++ * for subsequent chanspecs. + */ + channel[index].flags = IEEE80211_CHAN_NO_HT40 | + IEEE80211_CHAN_NO_80MHZ; +@@ -5436,16 +5410,8 @@ static int brcmf_construct_chaninfo(stru + IEEE80211_CHAN_NO_IR; + } + } +- if (index == band->n_channels) +- band->n_channels++; + } +- kfree(pbuf); +- return 0; + +-fail_band2g: +- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels); +- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]); +- wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; + fail_pbuf: + kfree(pbuf); + return err; +@@ -5778,7 +5744,12 @@ static void brcmf_wiphy_wowl_params(stru + + static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) + { ++ struct ieee80211_supported_band *band; + struct ieee80211_iface_combination ifc_combo; ++ __le32 bandlist[3]; ++ u32 n_bands; ++ int err, i; ++ + wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; + wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; + wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; +@@ -5820,7 +5791,52 @@ static int brcmf_setup_wiphy(struct wiph + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) + brcmf_wiphy_wowl_params(wiphy); + +- return brcmf_setup_wiphybands(wiphy); ++ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist, ++ sizeof(bandlist)); ++ if (err) { ++ brcmf_err("could not obtain band info: err=%d\n", err); ++ return err; ++ } ++ /* first entry in bandlist is number of bands */ ++ n_bands = le32_to_cpu(bandlist[0]); ++ for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) { ++ if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) { ++ band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz), ++ GFP_KERNEL); ++ if (!band) ++ return -ENOMEM; ++ ++ band->channels = kmemdup(&__wl_2ghz_channels, ++ sizeof(__wl_2ghz_channels), ++ GFP_KERNEL); ++ if (!band->channels) { ++ kfree(band); ++ return -ENOMEM; ++ } ++ ++ band->n_channels = ARRAY_SIZE(__wl_2ghz_channels); ++ wiphy->bands[IEEE80211_BAND_2GHZ] = band; ++ } ++ if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) { ++ band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz), ++ GFP_KERNEL); ++ if (!band) ++ return -ENOMEM; ++ ++ band->channels = kmemdup(&__wl_5ghz_channels, ++ sizeof(__wl_5ghz_channels), ++ GFP_KERNEL); ++ if (!band->channels) { ++ kfree(band); ++ return -ENOMEM; ++ } ++ ++ band->n_channels = ARRAY_SIZE(__wl_5ghz_channels); ++ wiphy->bands[IEEE80211_BAND_5GHZ] = band; ++ } ++ } ++ err = brcmf_setup_wiphybands(wiphy); ++ return err; + } + + static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) +@@ -6011,6 +6027,9 @@ static void brcmf_cfg80211_reg_notifier( + + static void brcmf_free_wiphy(struct wiphy *wiphy) + { ++ if (!wiphy) ++ return; ++ + kfree(wiphy->iface_combinations); + if (wiphy->bands[IEEE80211_BAND_2GHZ]) { + kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels); diff --git a/package/kernel/mac80211/patches/355-brcmfmac-update-wiphy-band-information-upon-updating.patch b/package/kernel/mac80211/patches/355-brcmfmac-update-wiphy-band-information-upon-updating.patch new file mode 100644 index 0000000000..a0c22eb411 --- /dev/null +++ b/package/kernel/mac80211/patches/355-brcmfmac-update-wiphy-band-information-upon-updating.patch @@ -0,0 +1,29 @@ +From: Arend van Spriel +Date: Tue, 14 Apr 2015 20:10:25 +0200 +Subject: [PATCH] brcmfmac: update wiphy band information upon updating + regulatory domain + +When change the country code the available channels may change. So +the wiphy bands should be updated accordingly. + +Reviewed-by: Daniel (Deognyoun) Kim +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -6022,7 +6022,11 @@ static void brcmf_cfg80211_reg_notifier( + memset(&ccreq, 0, sizeof(ccreq)); + ccreq.rev = cpu_to_le32(-1); + memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2)); +- brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq)); ++ if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) { ++ brcmf_err("firmware rejected country setting\n"); ++ return; ++ } ++ brcmf_setup_wiphybands(wiphy); + } + + static void brcmf_free_wiphy(struct wiphy *wiphy) diff --git a/package/kernel/mac80211/patches/356-brcmfmac-add-description-for-feature-flags.patch b/package/kernel/mac80211/patches/356-brcmfmac-add-description-for-feature-flags.patch new file mode 100644 index 0000000000..193f507d0d --- /dev/null +++ b/package/kernel/mac80211/patches/356-brcmfmac-add-description-for-feature-flags.patch @@ -0,0 +1,24 @@ +From: Arend van Spriel +Date: Tue, 14 Apr 2015 20:10:26 +0200 +Subject: [PATCH] brcmfmac: add description for feature flags + +Some feature flags were not described in the header file. Adding +the description. + +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h +@@ -19,7 +19,9 @@ + /* + * Features: + * ++ * MBSS: multiple BSSID support (eg. guest network in AP mode). + * MCHAN: multi-channel for concurrent P2P. ++ * WOWL: Wake-On-WLAN. + */ + #define BRCMF_FEAT_LIST \ + BRCMF_FEAT_DEF(MBSS) \ diff --git a/package/kernel/mac80211/patches/357-brcmfmac-make-scheduled-scan-support-conditional.patch b/package/kernel/mac80211/patches/357-brcmfmac-make-scheduled-scan-support-conditional.patch new file mode 100644 index 0000000000..42330b474e --- /dev/null +++ b/package/kernel/mac80211/patches/357-brcmfmac-make-scheduled-scan-support-conditional.patch @@ -0,0 +1,51 @@ +From: Arend van Spriel +Date: Tue, 14 Apr 2015 20:10:27 +0200 +Subject: [PATCH] brcmfmac: make scheduled scan support conditional + +The scheduled scan support depends on firmware supporting the PNO +feature. This feature is optional so add a feature flag for this +in the driver and announce scheduled scan support accordingly. + +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -5782,7 +5782,8 @@ static int brcmf_setup_wiphy(struct wiph + wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + wiphy->mgmt_stypes = brcmf_txrx_stypes; + wiphy->max_remain_on_channel_duration = 5000; +- brcmf_wiphy_pno_params(wiphy); ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) ++ brcmf_wiphy_pno_params(wiphy); + + /* vendor commands/events support */ + wiphy->vendor_commands = brcmf_vendor_cmds; +--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c +@@ -124,6 +124,7 @@ void brcmf_feat_attach(struct brcmf_pub + struct brcmf_if *ifp = drvr->iflist[0]; + + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan"); ++ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn"); + if (drvr->bus_if->wowl_supported) + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); + if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID) +--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h +@@ -21,11 +21,13 @@ + * + * MBSS: multiple BSSID support (eg. guest network in AP mode). + * MCHAN: multi-channel for concurrent P2P. ++ * PNO: preferred network offload. + * WOWL: Wake-On-WLAN. + */ + #define BRCMF_FEAT_LIST \ + BRCMF_FEAT_DEF(MBSS) \ + BRCMF_FEAT_DEF(MCHAN) \ ++ BRCMF_FEAT_DEF(PNO) \ + BRCMF_FEAT_DEF(WOWL) + /* + * Quirks: diff --git a/package/kernel/mac80211/patches/358-brcmfmac-add-support-for-BCM4324-rev-B5-chipset.patch b/package/kernel/mac80211/patches/358-brcmfmac-add-support-for-BCM4324-rev-B5-chipset.patch new file mode 100644 index 0000000000..b859d46894 --- /dev/null +++ b/package/kernel/mac80211/patches/358-brcmfmac-add-support-for-BCM4324-rev-B5-chipset.patch @@ -0,0 +1,43 @@ +From: Arend van Spriel +Date: Tue, 14 Apr 2015 20:10:28 +0200 +Subject: [PATCH] brcmfmac: add support for BCM4324 rev B5 chipset + +This patch adds support for the BCM4324 B5 revision. This device +is similar to BCM43241 from driver and firmware perspective. It +is known to be used in Lenovo Thinkpad Tablet devices. + +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +@@ -601,6 +601,8 @@ static const struct sdiod_drive_str sdio + #define BCM43241B0_NVRAM_NAME "brcm/brcmfmac43241b0-sdio.txt" + #define BCM43241B4_FIRMWARE_NAME "brcm/brcmfmac43241b4-sdio.bin" + #define BCM43241B4_NVRAM_NAME "brcm/brcmfmac43241b4-sdio.txt" ++#define BCM43241B5_FIRMWARE_NAME "brcm/brcmfmac43241b5-sdio.bin" ++#define BCM43241B5_NVRAM_NAME "brcm/brcmfmac43241b5-sdio.txt" + #define BCM4329_FIRMWARE_NAME "brcm/brcmfmac4329-sdio.bin" + #define BCM4329_NVRAM_NAME "brcm/brcmfmac4329-sdio.txt" + #define BCM4330_FIRMWARE_NAME "brcm/brcmfmac4330-sdio.bin" +@@ -628,6 +630,8 @@ MODULE_FIRMWARE(BCM43241B0_FIRMWARE_NAME + MODULE_FIRMWARE(BCM43241B0_NVRAM_NAME); + MODULE_FIRMWARE(BCM43241B4_FIRMWARE_NAME); + MODULE_FIRMWARE(BCM43241B4_NVRAM_NAME); ++MODULE_FIRMWARE(BCM43241B5_FIRMWARE_NAME); ++MODULE_FIRMWARE(BCM43241B5_NVRAM_NAME); + MODULE_FIRMWARE(BCM4329_FIRMWARE_NAME); + MODULE_FIRMWARE(BCM4329_NVRAM_NAME); + MODULE_FIRMWARE(BCM4330_FIRMWARE_NAME); +@@ -667,7 +671,8 @@ enum brcmf_firmware_type { + static const struct brcmf_firmware_names brcmf_fwname_data[] = { + { BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) }, + { BRCM_CC_43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) }, +- { BRCM_CC_43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) }, ++ { BRCM_CC_43241_CHIP_ID, 0x00000020, BRCMF_FIRMWARE_NVRAM(BCM43241B4) }, ++ { BRCM_CC_43241_CHIP_ID, 0xFFFFFFC0, BRCMF_FIRMWARE_NVRAM(BCM43241B5) }, + { BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) }, + { BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) }, + { BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) }, diff --git a/package/kernel/mac80211/patches/359-brcmfmac-process-interrupt-regardless-sdiod-state.patch b/package/kernel/mac80211/patches/359-brcmfmac-process-interrupt-regardless-sdiod-state.patch new file mode 100644 index 0000000000..d420308383 --- /dev/null +++ b/package/kernel/mac80211/patches/359-brcmfmac-process-interrupt-regardless-sdiod-state.patch @@ -0,0 +1,27 @@ +From: Arend van Spriel +Date: Tue, 14 Apr 2015 20:10:29 +0200 +Subject: [PATCH] brcmfmac: process interrupt regardless sdiod state + +When the sdio bus state is not ready to process we abort the +interrupt service routine. This is not wanted as it keeps the +interrupt source active. Better clear the interrupt source. + +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky (Zhenhui) Lin +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +@@ -3555,10 +3555,6 @@ void brcmf_sdio_isr(struct brcmf_sdio *b + return; + } + +- if (bus->sdiodev->state != BRCMF_SDIOD_DATA) { +- brcmf_err("bus is down. we have nothing to do\n"); +- return; +- } + /* Count the interrupt call */ + bus->sdcnt.intrcount++; + if (in_interrupt()) diff --git a/package/kernel/mac80211/patches/360-brcmfmac-fix-sdio-suspend-and-resume.patch b/package/kernel/mac80211/patches/360-brcmfmac-fix-sdio-suspend-and-resume.patch new file mode 100644 index 0000000000..ac5584ec3c --- /dev/null +++ b/package/kernel/mac80211/patches/360-brcmfmac-fix-sdio-suspend-and-resume.patch @@ -0,0 +1,68 @@ +From: Arend van Spriel +Date: Tue, 14 Apr 2015 20:10:30 +0200 +Subject: [PATCH] brcmfmac: fix sdio suspend and resume + +commit 330b4e4be937 ("brcmfmac: Add wowl support for SDIO devices.") +changed the behaviour by removing the MMC_PM_KEEP_POWER flag for +non-wowl scenario, which needs to be restored. Another necessary +change is to mark the card as being non-removable. With this in place +the suspend resume test passes successfully doing: + + # echo devices > /sys/power/pm_test + # echo mem > /sys/power/state + +Note that power may still be switched off when system is going +in S3 state. + +Reported-by: Fu, Zhonghui < +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky (Zhenhui) Lin +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +@@ -1011,6 +1011,14 @@ static int brcmf_sdiod_remove(struct brc + return 0; + } + ++static void brcmf_sdiod_host_fixup(struct mmc_host *host) ++{ ++ /* runtime-pm powers off the device */ ++ pm_runtime_forbid(host->parent); ++ /* avoid removal detection upon resume */ ++ host->caps |= MMC_CAP_NONREMOVABLE; ++} ++ + static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) + { + struct sdio_func *func; +@@ -1076,7 +1084,7 @@ static int brcmf_sdiod_probe(struct brcm + ret = -ENODEV; + goto out; + } +- pm_runtime_forbid(host->parent); ++ brcmf_sdiod_host_fixup(host); + out: + if (ret) + brcmf_sdiod_remove(sdiodev); +@@ -1246,15 +1254,15 @@ static int brcmf_ops_sdio_suspend(struct + brcmf_sdiod_freezer_on(sdiodev); + brcmf_sdio_wd_timer(sdiodev->bus, 0); + ++ sdio_flags = MMC_PM_KEEP_POWER; + if (sdiodev->wowl_enabled) { +- sdio_flags = MMC_PM_KEEP_POWER; + if (sdiodev->pdata->oob_irq_supported) + enable_irq_wake(sdiodev->pdata->oob_irq_nr); + else +- sdio_flags = MMC_PM_WAKE_SDIO_IRQ; +- if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags)) +- brcmf_err("Failed to set pm_flags %x\n", sdio_flags); ++ sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; + } ++ if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags)) ++ brcmf_err("Failed to set pm_flags %x\n", sdio_flags); + return 0; + } + diff --git a/package/kernel/mac80211/patches/361-brcmfmac-add-support-for-BCM4358-PCIe-device.patch b/package/kernel/mac80211/patches/361-brcmfmac-add-support-for-BCM4358-PCIe-device.patch new file mode 100644 index 0000000000..a521b65d0f --- /dev/null +++ b/package/kernel/mac80211/patches/361-brcmfmac-add-support-for-BCM4358-PCIe-device.patch @@ -0,0 +1,77 @@ +From: Arend van Spriel +Date: Tue, 14 Apr 2015 20:10:31 +0200 +Subject: [PATCH] brcmfmac: add support for BCM4358 PCIe device + +This patch adds support for the BCM4358 2x2 11ac device. + +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c +@@ -649,6 +649,7 @@ static u32 brcmf_chip_tcm_rambase(struct + case BRCM_CC_43567_CHIP_ID: + case BRCM_CC_43569_CHIP_ID: + case BRCM_CC_43570_CHIP_ID: ++ case BRCM_CC_4358_CHIP_ID: + case BRCM_CC_43602_CHIP_ID: + return 0x180000; + default: +--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +@@ -51,6 +51,8 @@ enum brcmf_pcie_state { + #define BRCMF_PCIE_4356_NVRAM_NAME "brcm/brcmfmac4356-pcie.txt" + #define BRCMF_PCIE_43570_FW_NAME "brcm/brcmfmac43570-pcie.bin" + #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_FW_UP_TIMEOUT 2000 /* msec */ + +@@ -189,6 +191,8 @@ MODULE_FIRMWARE(BRCMF_PCIE_4356_FW_NAME) + MODULE_FIRMWARE(BRCMF_PCIE_4356_NVRAM_NAME); + 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); + + + struct brcmf_pcie_console { +@@ -1333,6 +1337,10 @@ static int brcmf_pcie_get_fwnames(struct + fw_name = BRCMF_PCIE_43570_FW_NAME; + nvram_name = BRCMF_PCIE_43570_NVRAM_NAME; + break; ++ case BRCM_CC_4358_CHIP_ID: ++ fw_name = BRCMF_PCIE_4358_FW_NAME; ++ nvram_name = BRCMF_PCIE_4358_NVRAM_NAME; ++ break; + default: + brcmf_err("Unsupported chip 0x%04x\n", devinfo->ci->chip); + return -ENODEV; +@@ -1850,6 +1858,7 @@ static struct pci_device_id brcmf_pcie_d + BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID), ++ BRCMF_PCIE_DEVICE(BRCM_PCIE_4358_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID), +--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h ++++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +@@ -45,6 +45,7 @@ + #define BRCM_CC_43567_CHIP_ID 43567 + #define BRCM_CC_43569_CHIP_ID 43569 + #define BRCM_CC_43570_CHIP_ID 43570 ++#define BRCM_CC_4358_CHIP_ID 0x4358 + #define BRCM_CC_43602_CHIP_ID 43602 + + /* USB Device IDs */ +@@ -59,6 +60,7 @@ + #define BRCM_PCIE_4356_DEVICE_ID 0x43ec + #define BRCM_PCIE_43567_DEVICE_ID 0x43d3 + #define BRCM_PCIE_43570_DEVICE_ID 0x43d9 ++#define BRCM_PCIE_4358_DEVICE_ID 0x43e9 + #define BRCM_PCIE_43602_DEVICE_ID 0x43ba + #define BRCM_PCIE_43602_2G_DEVICE_ID 0x43bb + #define BRCM_PCIE_43602_5G_DEVICE_ID 0x43bc diff --git a/package/kernel/mac80211/patches/362-brcmfmac-add-additional-43602-pcie-device-id.patch b/package/kernel/mac80211/patches/362-brcmfmac-add-additional-43602-pcie-device-id.patch new file mode 100644 index 0000000000..bcbb984d42 --- /dev/null +++ b/package/kernel/mac80211/patches/362-brcmfmac-add-additional-43602-pcie-device-id.patch @@ -0,0 +1,30 @@ +From: Hante Meuleman +Date: Tue, 14 Apr 2015 20:10:32 +0200 +Subject: [PATCH] brcmfmac: add additional 43602 pcie device id. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +@@ -1862,6 +1862,7 @@ static struct pci_device_id brcmf_pcie_d + BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID), + 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), + { /* end: all zeroes */ } + }; + +--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h ++++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +@@ -64,6 +64,7 @@ + #define BRCM_PCIE_43602_DEVICE_ID 0x43ba + #define BRCM_PCIE_43602_2G_DEVICE_ID 0x43bb + #define BRCM_PCIE_43602_5G_DEVICE_ID 0x43bc ++#define BRCM_PCIE_43602_RAW_DEVICE_ID 43602 + + /* brcmsmac IDs */ + #define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ diff --git a/package/kernel/mac80211/patches/363-brcmfmac-Add-support-for-multiple-PCIE-devices-in-nv.patch b/package/kernel/mac80211/patches/363-brcmfmac-Add-support-for-multiple-PCIE-devices-in-nv.patch new file mode 100644 index 0000000000..5f9bbeaf5c --- /dev/null +++ b/package/kernel/mac80211/patches/363-brcmfmac-Add-support-for-multiple-PCIE-devices-in-nv.patch @@ -0,0 +1,351 @@ +From: Hante Meuleman +Date: Tue, 14 Apr 2015 20:10:33 +0200 +Subject: [PATCH] brcmfmac: Add support for multiple PCIE devices in + nvram. + +With PCIE it is possible to support multiple devices with the +same device type. They all load the same nvram file. In order to +support this the nvram can specify which part of the nvram is +for which pcie device. This patch adds support for these new +types of nvram files. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Daniel (Deognyoun) Kim +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +@@ -23,6 +23,10 @@ + #include "debug.h" + #include "firmware.h" + ++#define BRCMF_FW_MAX_NVRAM_SIZE 64000 ++#define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */ ++#define BRCMF_FW_NVRAM_PCIEDEV_LEN 9 /* pcie/1/4/ */ ++ + char brcmf_firmware_path[BRCMF_FW_PATH_LEN]; + module_param_string(firmware_path, brcmf_firmware_path, + BRCMF_FW_PATH_LEN, 0440); +@@ -46,6 +50,8 @@ enum nvram_parser_state { + * @column: current column in line. + * @pos: byte offset in input buffer. + * @entry: start position of key,value entry. ++ * @multi_dev_v1: detect pcie multi device v1 (compressed). ++ * @multi_dev_v2: detect pcie multi device v2. + */ + struct nvram_parser { + enum nvram_parser_state state; +@@ -56,6 +62,8 @@ struct nvram_parser { + u32 column; + u32 pos; + u32 entry; ++ bool multi_dev_v1; ++ bool multi_dev_v2; + }; + + static bool is_nvram_char(char c) +@@ -108,6 +116,10 @@ static enum nvram_parser_state brcmf_nvr + st = COMMENT; + else + st = VALUE; ++ if (strncmp(&nvp->fwnv->data[nvp->entry], "devpath", 7) == 0) ++ nvp->multi_dev_v1 = true; ++ if (strncmp(&nvp->fwnv->data[nvp->entry], "pcie/", 5) == 0) ++ nvp->multi_dev_v2 = true; + } else if (!is_nvram_char(c)) { + brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n", + nvp->line, nvp->column); +@@ -133,6 +145,8 @@ brcmf_nvram_handle_value(struct nvram_pa + ekv = (u8 *)&nvp->fwnv->data[nvp->pos]; + skv = (u8 *)&nvp->fwnv->data[nvp->entry]; + cplen = ekv - skv; ++ if (nvp->nvram_len + cplen + 1 >= BRCMF_FW_MAX_NVRAM_SIZE) ++ return END; + /* copy to output buffer */ + memcpy(&nvp->nvram[nvp->nvram_len], skv, cplen); + nvp->nvram_len += cplen; +@@ -180,10 +194,18 @@ static enum nvram_parser_state + static int brcmf_init_nvram_parser(struct nvram_parser *nvp, + const struct firmware *nv) + { ++ size_t size; ++ + memset(nvp, 0, sizeof(*nvp)); + nvp->fwnv = nv; ++ /* Limit size to MAX_NVRAM_SIZE, some files contain lot of comment */ ++ if (nv->size > BRCMF_FW_MAX_NVRAM_SIZE) ++ size = BRCMF_FW_MAX_NVRAM_SIZE; ++ else ++ size = nv->size; + /* Alloc for extra 0 byte + roundup by 4 + length field */ +- nvp->nvram = kzalloc(nv->size + 1 + 3 + sizeof(u32), GFP_KERNEL); ++ size += 1 + 3 + sizeof(u32); ++ nvp->nvram = kzalloc(size, GFP_KERNEL); + if (!nvp->nvram) + return -ENOMEM; + +@@ -192,12 +214,136 @@ static int brcmf_init_nvram_parser(struc + return 0; + } + ++/* brcmf_fw_strip_multi_v1 :Some nvram files contain settings for multiple ++ * devices. Strip it down for one device, use domain_nr/bus_nr to determine ++ * which data is to be returned. v1 is the version where nvram is stored ++ * compressed and "devpath" maps to index for valid entries. ++ */ ++static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr, ++ u16 bus_nr) ++{ ++ u32 i, j; ++ bool found; ++ u8 *nvram; ++ u8 id; ++ ++ nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL); ++ if (!nvram) ++ goto fail; ++ ++ /* min length: devpath0=pcie/1/4/ + 0:x=y */ ++ if (nvp->nvram_len < BRCMF_FW_NVRAM_DEVPATH_LEN + 6) ++ goto fail; ++ ++ /* First search for the devpathX and see if it is the configuration ++ * for domain_nr/bus_nr. Search complete nvp ++ */ ++ found = false; ++ i = 0; ++ while (i < nvp->nvram_len - BRCMF_FW_NVRAM_DEVPATH_LEN) { ++ /* Format: devpathX=pcie/Y/Z/ ++ * Y = domain_nr, Z = bus_nr, X = virtual ID ++ */ ++ if ((strncmp(&nvp->nvram[i], "devpath", 7) == 0) && ++ (strncmp(&nvp->nvram[i + 8], "=pcie/", 6) == 0)) { ++ if (((nvp->nvram[i + 14] - '0') == domain_nr) && ++ ((nvp->nvram[i + 16] - '0') == bus_nr)) { ++ id = nvp->nvram[i + 7] - '0'; ++ found = true; ++ break; ++ } ++ } ++ while (nvp->nvram[i] != 0) ++ i++; ++ i++; ++ } ++ if (!found) ++ goto fail; ++ ++ /* Now copy all valid entries, release old nvram and assign new one */ ++ i = 0; ++ j = 0; ++ while (i < nvp->nvram_len) { ++ if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) { ++ i += 2; ++ while (nvp->nvram[i] != 0) { ++ nvram[j] = nvp->nvram[i]; ++ i++; ++ j++; ++ } ++ nvram[j] = 0; ++ j++; ++ } ++ while (nvp->nvram[i] != 0) ++ i++; ++ i++; ++ } ++ kfree(nvp->nvram); ++ nvp->nvram = nvram; ++ nvp->nvram_len = j; ++ return; ++ ++fail: ++ kfree(nvram); ++ nvp->nvram_len = 0; ++} ++ ++/* brcmf_fw_strip_multi_v2 :Some nvram files contain settings for multiple ++ * devices. Strip it down for one device, use domain_nr/bus_nr to determine ++ * which data is to be returned. v2 is the version where nvram is stored ++ * uncompressed, all relevant valid entries are identified by ++ * pcie/domain_nr/bus_nr: ++ */ ++static void brcmf_fw_strip_multi_v2(struct nvram_parser *nvp, u16 domain_nr, ++ u16 bus_nr) ++{ ++ u32 i, j; ++ u8 *nvram; ++ ++ nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL); ++ if (!nvram) ++ goto fail; ++ ++ /* Copy all valid entries, release old nvram and assign new one. ++ * Valid entries are of type pcie/X/Y/ where X = domain_nr and ++ * Y = bus_nr. ++ */ ++ i = 0; ++ j = 0; ++ while (i < nvp->nvram_len - BRCMF_FW_NVRAM_PCIEDEV_LEN) { ++ if ((strncmp(&nvp->nvram[i], "pcie/", 5) == 0) && ++ (nvp->nvram[i + 6] == '/') && (nvp->nvram[i + 8] == '/') && ++ ((nvp->nvram[i + 5] - '0') == domain_nr) && ++ ((nvp->nvram[i + 7] - '0') == bus_nr)) { ++ i += BRCMF_FW_NVRAM_PCIEDEV_LEN; ++ while (nvp->nvram[i] != 0) { ++ nvram[j] = nvp->nvram[i]; ++ i++; ++ j++; ++ } ++ nvram[j] = 0; ++ j++; ++ } ++ while (nvp->nvram[i] != 0) ++ i++; ++ i++; ++ } ++ kfree(nvp->nvram); ++ nvp->nvram = nvram; ++ nvp->nvram_len = j; ++ return; ++fail: ++ kfree(nvram); ++ nvp->nvram_len = 0; ++} ++ + /* brcmf_nvram_strip :Takes a buffer of "=\n" lines read from a fil + * and ending in a NUL. Removes carriage returns, empty lines, comment lines, + * and converts newlines to NULs. Shortens buffer as needed and pads with NULs. + * End of buffer is completed with token identifying length of buffer. + */ +-static void *brcmf_fw_nvram_strip(const struct firmware *nv, u32 *new_length) ++static void *brcmf_fw_nvram_strip(const struct firmware *nv, u32 *new_length, ++ u16 domain_nr, u16 bus_nr) + { + struct nvram_parser nvp; + u32 pad; +@@ -212,6 +358,16 @@ static void *brcmf_fw_nvram_strip(const + if (nvp.state == END) + break; + } ++ if (nvp.multi_dev_v1) ++ brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr); ++ else if (nvp.multi_dev_v2) ++ brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr); ++ ++ if (nvp.nvram_len == 0) { ++ kfree(nvp.nvram); ++ return NULL; ++ } ++ + pad = nvp.nvram_len; + *new_length = roundup(nvp.nvram_len + 1, 4); + while (pad != *new_length) { +@@ -239,6 +395,8 @@ struct brcmf_fw { + u16 flags; + const struct firmware *code; + const char *nvram_name; ++ u16 domain_nr; ++ u16 bus_nr; + void (*done)(struct device *dev, const struct firmware *fw, + void *nvram_image, u32 nvram_len); + }; +@@ -254,7 +412,8 @@ static void brcmf_fw_request_nvram_done( + goto fail; + + if (fw) { +- nvram = brcmf_fw_nvram_strip(fw, &nvram_length); ++ nvram = brcmf_fw_nvram_strip(fw, &nvram_length, ++ fwctx->domain_nr, fwctx->bus_nr); + release_firmware(fw); + if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) + goto fail; +@@ -309,11 +468,12 @@ fail: + kfree(fwctx); + } + +-int brcmf_fw_get_firmwares(struct device *dev, u16 flags, +- const char *code, const char *nvram, +- void (*fw_cb)(struct device *dev, +- const struct firmware *fw, +- void *nvram_image, u32 nvram_len)) ++int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags, ++ const char *code, const char *nvram, ++ void (*fw_cb)(struct device *dev, ++ const struct firmware *fw, ++ void *nvram_image, u32 nvram_len), ++ u16 domain_nr, u16 bus_nr) + { + struct brcmf_fw *fwctx; + +@@ -333,8 +493,21 @@ int brcmf_fw_get_firmwares(struct device + fwctx->done = fw_cb; + if (flags & BRCMF_FW_REQUEST_NVRAM) + fwctx->nvram_name = nvram; ++ fwctx->domain_nr = domain_nr; ++ fwctx->bus_nr = bus_nr; + + return request_firmware_nowait(THIS_MODULE, true, code, dev, + GFP_KERNEL, fwctx, + brcmf_fw_request_code_done); + } ++ ++int brcmf_fw_get_firmwares(struct device *dev, u16 flags, ++ const char *code, const char *nvram, ++ void (*fw_cb)(struct device *dev, ++ const struct firmware *fw, ++ void *nvram_image, u32 nvram_len)) ++{ ++ return brcmf_fw_get_firmwares_pcie(dev, flags, code, nvram, fw_cb, 0, ++ 0); ++} ++ +--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h +@@ -32,6 +32,12 @@ void brcmf_fw_nvram_free(void *nvram); + * fails it will not use the callback, but call device_release_driver() + * instead which will call the driver .remove() callback. + */ ++int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags, ++ const char *code, const char *nvram, ++ void (*fw_cb)(struct device *dev, ++ const struct firmware *fw, ++ void *nvram_image, u32 nvram_len), ++ u16 domain_nr, u16 bus_nr); + int brcmf_fw_get_firmwares(struct device *dev, u16 flags, + const char *code, const char *nvram, + void (*fw_cb)(struct device *dev, +--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +@@ -1649,8 +1649,13 @@ brcmf_pcie_probe(struct pci_dev *pdev, c + struct brcmf_pciedev_info *devinfo; + struct brcmf_pciedev *pcie_bus_dev; + struct brcmf_bus *bus; ++ u16 domain_nr; ++ u16 bus_nr; + +- brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device); ++ domain_nr = pci_domain_nr(pdev->bus) + 1; ++ bus_nr = pdev->bus->number; ++ brcmf_dbg(PCIE, "Enter %x:%x (%d/%d)\n", pdev->vendor, pdev->device, ++ domain_nr, bus_nr); + + ret = -ENOMEM; + devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); +@@ -1699,10 +1704,10 @@ brcmf_pcie_probe(struct pci_dev *pdev, c + if (ret) + goto fail_bus; + +- ret = brcmf_fw_get_firmwares(bus->dev, BRCMF_FW_REQUEST_NVRAM | +- BRCMF_FW_REQ_NV_OPTIONAL, +- devinfo->fw_name, devinfo->nvram_name, +- brcmf_pcie_setup); ++ ret = brcmf_fw_get_firmwares_pcie(bus->dev, BRCMF_FW_REQUEST_NVRAM | ++ BRCMF_FW_REQ_NV_OPTIONAL, ++ devinfo->fw_name, devinfo->nvram_name, ++ brcmf_pcie_setup, domain_nr, bus_nr); + if (ret == 0) + return 0; + fail_bus: