From: Hante Meuleman Date: Wed, 25 Nov 2015 11:32:43 +0100 Subject: [PATCH] brcmfmac: Add beamforming support. Some devices support beamforming. This patch enables tx beamforming if supported and reports beamforming capabilities per channel if supported. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -5671,7 +5671,8 @@ static __le16 brcmf_get_mcs_map(u32 ncha } static void brcmf_update_vht_cap(struct ieee80211_supported_band *band, - u32 bw_cap[2], u32 nchain) + u32 bw_cap[2], u32 nchain, u32 txstreams, + u32 txbf_bfe_cap, u32 txbf_bfr_cap) { __le16 mcs_map; @@ -5690,6 +5691,25 @@ static void brcmf_update_vht_cap(struct mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9); band->vht_cap.vht_mcs.rx_mcs_map = mcs_map; band->vht_cap.vht_mcs.tx_mcs_map = mcs_map; + + /* Beamforming support information */ + if (txbf_bfe_cap & BRCMF_TXBF_SU_BFE_CAP) + band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + if (txbf_bfe_cap & BRCMF_TXBF_MU_BFE_CAP) + band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + if (txbf_bfr_cap & BRCMF_TXBF_SU_BFR_CAP) + band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + if (txbf_bfr_cap & BRCMF_TXBF_MU_BFR_CAP) + band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; + + if ((txbf_bfe_cap || txbf_bfr_cap) && (txstreams > 1)) { + band->vht_cap.cap |= + (2 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); + band->vht_cap.cap |= ((txstreams - 1) << + IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT); + band->vht_cap.cap |= + IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB; + } } static int brcmf_setup_wiphybands(struct wiphy *wiphy) @@ -5704,6 +5724,9 @@ static int brcmf_setup_wiphybands(struct int err; s32 i; struct ieee80211_supported_band *band; + u32 txstreams = 0; + u32 txbf_bfe_cap = 0; + u32 txbf_bfr_cap = 0; (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode); err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode); @@ -5732,6 +5755,14 @@ static int brcmf_setup_wiphybands(struct return err; } + if (vhtmode) { + (void)brcmf_fil_iovar_int_get(ifp, "txstreams", &txstreams); + (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfe_cap", + &txbf_bfe_cap); + (void)brcmf_fil_iovar_int_get(ifp, "txbf_bfr_cap", + &txbf_bfr_cap); + } + wiphy = cfg_to_wiphy(cfg); for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) { band = wiphy->bands[i]; @@ -5741,7 +5772,8 @@ static int brcmf_setup_wiphybands(struct if (nmode) brcmf_update_ht_cap(band, bw_cap, nchain); if (vhtmode) - brcmf_update_vht_cap(band, bw_cap, nchain); + brcmf_update_vht_cap(band, bw_cap, nchain, txstreams, + txbf_bfe_cap, txbf_bfr_cap); } return 0; --- a/drivers/net/wireless/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/common.c @@ -153,6 +153,9 @@ int brcmf_c_preinit_dcmds(struct brcmf_i goto done; } + /* Enable tx beamforming, errors can be ignored (not supported) */ + (void)brcmf_fil_iovar_int_set(ifp, "txbf", 1); + /* do bus specific preinit here */ err = brcmf_bus_preinit(ifp->drvr->bus_if); done: --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h @@ -121,6 +121,11 @@ #define BRCMF_MAX_ASSOCLIST 128 +#define BRCMF_TXBF_SU_BFE_CAP BIT(0) +#define BRCMF_TXBF_MU_BFE_CAP BIT(1) +#define BRCMF_TXBF_SU_BFR_CAP BIT(0) +#define BRCMF_TXBF_MU_BFR_CAP BIT(1) + /* join preference types for join_pref iovar */ enum brcmf_join_pref_types { BRCMF_JOIN_PREF_RSSI = 1,