mirror of https://github.com/hak5/openwrt.git
mac80211: backport brcmfmac to support multiple devices NVRAM
Signed-off-by: Rafał Miłecki <zajec5@gmail.com> SVN-Revision: 45577lede-17.01
parent
c1a7e13587
commit
84a3e668fc
|
@ -0,0 +1,300 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
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 <meuleman@broadcom.com>
|
||||
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
@@ -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);
|
|
@ -0,0 +1,29 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
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 <dekim@broadcom.com>
|
||||
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
@@ -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)
|
|
@ -0,0 +1,24 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
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 <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/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) \
|
|
@ -0,0 +1,51 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
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 <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
@@ -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:
|
|
@ -0,0 +1,43 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
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 <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/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) },
|
|
@ -0,0 +1,27 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
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 <meuleman@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- 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())
|
|
@ -0,0 +1,68 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
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 <<zhonghui.fu@linux.intel.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
From: Arend van Spriel <arend@broadcom.com>
|
||||
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 <pieterpg@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- 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
|
|
@ -0,0 +1,30 @@
|
|||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
Date: Tue, 14 Apr 2015 20:10:32 +0200
|
||||
Subject: [PATCH] brcmfmac: add additional 43602 pcie device id.
|
||||
|
||||
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>
|
||||
---
|
||||
|
||||
--- 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 */
|
|
@ -0,0 +1,351 @@
|
|||
From: Hante Meuleman <meuleman@broadcom.com>
|
||||
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 <arend@broadcom.com>
|
||||
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
|
||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
||||
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
|
||||
Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
|
||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
||||
---
|
||||
|
||||
--- 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 "<var>=<value>\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:
|
Loading…
Reference in New Issue