aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/370-0003-brcmfmac-Fix-set-and-get-tx-power-functions.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel/mac80211/patches/370-0003-brcmfmac-Fix-set-and-get-tx-power-functions.patch')
-rw-r--r--package/kernel/mac80211/patches/370-0003-brcmfmac-Fix-set-and-get-tx-power-functions.patch218
1 files changed, 218 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/370-0003-brcmfmac-Fix-set-and-get-tx-power-functions.patch b/package/kernel/mac80211/patches/370-0003-brcmfmac-Fix-set-and-get-tx-power-functions.patch
new file mode 100644
index 0000000000..62fdd8d745
--- /dev/null
+++ b/package/kernel/mac80211/patches/370-0003-brcmfmac-Fix-set-and-get-tx-power-functions.patch
@@ -0,0 +1,218 @@
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 18 Sep 2015 22:08:06 +0200
+Subject: [PATCH] brcmfmac: Fix set and get tx-power functions.
+
+Implementation of tx-power (get and set) related functions are
+still assuming mW interface. This is wrong as functions use dbm
+(or mbm) nowadays. As a result a tx power configuration could
+result in wrong power configuration.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -236,89 +236,6 @@ static int brcmf_roamoff;
+ module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
+ MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
+
+-/* Quarter dBm units to mW
+- * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
+- * Table is offset so the last entry is largest mW value that fits in
+- * a u16.
+- */
+-
+-#define QDBM_OFFSET 153 /* Offset for first entry */
+-#define QDBM_TABLE_LEN 40 /* Table size */
+-
+-/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
+- * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
+- */
+-#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
+-
+-/* Largest mW value that will round down to the last table entry,
+- * QDBM_OFFSET + QDBM_TABLE_LEN-1.
+- * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
+- * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
+- */
+-#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
+-
+-static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
+-/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
+-/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
+-/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
+-/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
+-/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
+-/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
+-};
+-
+-static u16 brcmf_qdbm_to_mw(u8 qdbm)
+-{
+- uint factor = 1;
+- int idx = qdbm - QDBM_OFFSET;
+-
+- if (idx >= QDBM_TABLE_LEN)
+- /* clamp to max u16 mW value */
+- return 0xFFFF;
+-
+- /* scale the qdBm index up to the range of the table 0-40
+- * where an offset of 40 qdBm equals a factor of 10 mW.
+- */
+- while (idx < 0) {
+- idx += 40;
+- factor *= 10;
+- }
+-
+- /* return the mW value scaled down to the correct factor of 10,
+- * adding in factor/2 to get proper rounding.
+- */
+- return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
+-}
+-
+-static u8 brcmf_mw_to_qdbm(u16 mw)
+-{
+- u8 qdbm;
+- int offset;
+- uint mw_uint = mw;
+- uint boundary;
+-
+- /* handle boundary case */
+- if (mw_uint <= 1)
+- return 0;
+-
+- offset = QDBM_OFFSET;
+-
+- /* move mw into the range of the table */
+- while (mw_uint < QDBM_TABLE_LOW_BOUND) {
+- mw_uint *= 10;
+- offset -= 40;
+- }
+-
+- for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
+- boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
+- nqdBm_to_mW_map[qdbm]) / 2;
+- if (mw_uint < boundary)
+- break;
+- }
+-
+- qdbm += (u8) offset;
+-
+- return qdbm;
+-}
+
+ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
+ struct cfg80211_chan_def *ch)
+@@ -2016,16 +1933,14 @@ static s32
+ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_tx_power_setting type, s32 mbm)
+ {
+-
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = cfg_to_ndev(cfg);
+ struct brcmf_if *ifp = netdev_priv(ndev);
+- u16 txpwrmw;
+- s32 err = 0;
+- s32 disable = 0;
+- s32 dbm = MBM_TO_DBM(mbm);
++ s32 err;
++ s32 disable;
++ u32 qdbm = 127;
+
+- brcmf_dbg(TRACE, "Enter\n");
++ brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+@@ -2034,12 +1949,20 @@ brcmf_cfg80211_set_tx_power(struct wiphy
+ break;
+ case NL80211_TX_POWER_LIMITED:
+ case NL80211_TX_POWER_FIXED:
+- if (dbm < 0) {
++ if (mbm < 0) {
+ brcmf_err("TX_POWER_FIXED - dbm is negative\n");
+ err = -EINVAL;
+ goto done;
+ }
++ qdbm = MBM_TO_DBM(4 * mbm);
++ if (qdbm > 127)
++ qdbm = 127;
++ qdbm |= WL_TXPWR_OVERRIDE;
+ break;
++ default:
++ brcmf_err("Unsupported type %d\n", type);
++ err = -EINVAL;
++ goto done;
+ }
+ /* Make sure radio is off or on as far as software is concerned */
+ disable = WL_RADIO_SW_DISABLE << 16;
+@@ -2047,52 +1970,44 @@ brcmf_cfg80211_set_tx_power(struct wiphy
+ if (err)
+ brcmf_err("WLC_SET_RADIO error (%d)\n", err);
+
+- if (dbm > 0xffff)
+- txpwrmw = 0xffff;
+- else
+- txpwrmw = (u16) dbm;
+- err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
+- (s32)brcmf_mw_to_qdbm(txpwrmw));
++ err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
+ if (err)
+ brcmf_err("qtxpower error (%d)\n", err);
+- cfg->conf->tx_power = dbm;
+
+ done:
+- brcmf_dbg(TRACE, "Exit\n");
++ brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
+ return err;
+ }
+
+-static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
+- struct wireless_dev *wdev,
+- s32 *dbm)
++static s32
++brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
++ s32 *dbm)
+ {
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+- s32 txpwrdbm;
+- u8 result;
+- s32 err = 0;
++ struct net_device *ndev = cfg_to_ndev(cfg);
++ struct brcmf_if *ifp = netdev_priv(ndev);
++ s32 qdbm = 0;
++ s32 err;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (!check_vif_up(ifp->vif))
+ return -EIO;
+
+- err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
++ err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
+ if (err) {
+ brcmf_err("error (%d)\n", err);
+ goto done;
+ }
+-
+- result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
+- *dbm = (s32) brcmf_qdbm_to_mw(result);
++ *dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
+
+ done:
+- brcmf_dbg(TRACE, "Exit\n");
++ brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
+ return err;
+ }
+
+ static s32
+ brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
+- u8 key_idx, bool unicast, bool multicast)
++ u8 key_idx, bool unicast, bool multicast)
+ {
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ u32 index;