Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60dc35ef authored by Hante Meuleman's avatar Hante Meuleman Committed by Kalle Valo
Browse files

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: default avatarArend Van Spriel <arend@broadcom.com>
Reviewed-by: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent e3c92cb2
Loading
Loading
Loading
Loading
+26 −111
Original line number Original line Diff line number Diff line
@@ -236,89 +236,6 @@ static int brcmf_roamoff;
module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
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,
static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
			       struct cfg80211_chan_def *ch)
			       struct cfg80211_chan_def *ch)
@@ -2017,16 +1934,14 @@ static s32
brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
			    enum nl80211_tx_power_setting type, s32 mbm)
			    enum nl80211_tx_power_setting type, s32 mbm)
{
{

	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct net_device *ndev = cfg_to_ndev(cfg);
	struct net_device *ndev = cfg_to_ndev(cfg);
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_if *ifp = netdev_priv(ndev);
	u16 txpwrmw;
	s32 err;
	s32 err = 0;
	s32 disable;
	s32 disable = 0;
	u32 qdbm = 127;
	s32 dbm = MBM_TO_DBM(mbm);


	brcmf_dbg(TRACE, "Enter\n");
	brcmf_dbg(TRACE, "Enter %d %d\n", type, mbm);
	if (!check_vif_up(ifp->vif))
	if (!check_vif_up(ifp->vif))
		return -EIO;
		return -EIO;


@@ -2035,12 +1950,20 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
		break;
		break;
	case NL80211_TX_POWER_LIMITED:
	case NL80211_TX_POWER_LIMITED:
	case NL80211_TX_POWER_FIXED:
	case NL80211_TX_POWER_FIXED:
		if (dbm < 0) {
		if (mbm < 0) {
			brcmf_err("TX_POWER_FIXED - dbm is negative\n");
			brcmf_err("TX_POWER_FIXED - dbm is negative\n");
			err = -EINVAL;
			err = -EINVAL;
			goto done;
			goto done;
		}
		}
		qdbm =  MBM_TO_DBM(4 * mbm);
		if (qdbm > 127)
			qdbm = 127;
		qdbm |= WL_TXPWR_OVERRIDE;
		break;
		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 */
	/* Make sure radio is off or on as far as software is concerned */
	disable = WL_RADIO_SW_DISABLE << 16;
	disable = WL_RADIO_SW_DISABLE << 16;
@@ -2048,46 +1971,38 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
	if (err)
	if (err)
		brcmf_err("WLC_SET_RADIO error (%d)\n", err);
		brcmf_err("WLC_SET_RADIO error (%d)\n", err);


	if (dbm > 0xffff)
	err = brcmf_fil_iovar_int_set(ifp, "qtxpower", qdbm);
		txpwrmw = 0xffff;
	else
		txpwrmw = (u16) dbm;
	err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
				      (s32)brcmf_mw_to_qdbm(txpwrmw));
	if (err)
	if (err)
		brcmf_err("qtxpower error (%d)\n", err);
		brcmf_err("qtxpower error (%d)\n", err);
	cfg->conf->tx_power = dbm;


done:
done:
	brcmf_dbg(TRACE, "Exit\n");
	brcmf_dbg(TRACE, "Exit %d (qdbm)\n", qdbm & ~WL_TXPWR_OVERRIDE);
	return err;
	return err;
}
}


static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
static s32
				       struct wireless_dev *wdev,
brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
			    s32 *dbm)
			    s32 *dbm)
{
{
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
	struct net_device *ndev = cfg_to_ndev(cfg);
	s32 txpwrdbm;
	struct brcmf_if *ifp = netdev_priv(ndev);
	u8 result;
	s32 qdbm = 0;
	s32 err = 0;
	s32 err;


	brcmf_dbg(TRACE, "Enter\n");
	brcmf_dbg(TRACE, "Enter\n");
	if (!check_vif_up(ifp->vif))
	if (!check_vif_up(ifp->vif))
		return -EIO;
		return -EIO;


	err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
	err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
	if (err) {
	if (err) {
		brcmf_err("error (%d)\n", err);
		brcmf_err("error (%d)\n", err);
		goto done;
		goto done;
	}
	}

	*dbm = (qdbm & ~WL_TXPWR_OVERRIDE) / 4;
	result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
	*dbm = (s32) brcmf_qdbm_to_mw(result);


done:
done:
	brcmf_dbg(TRACE, "Exit\n");
	brcmf_dbg(TRACE, "Exit (0x%x %d)\n", qdbm, *dbm);
	return err;
	return err;
}
}