mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-26 21:20:52 +07:00
carl9170: set beacon xmit power to the max
Harshal Chhaya discovered during network tests, that several of his clients dropped-off the network. The captured packets shows that the beacons sent by the AP are at a much lower power than the other data packets. The reason for this mishap: The driver never updated the beacon phy register, so all beacons were always sent at the lowest power. Reference: http://marc.info/?l=linux-wireless&m=131067225105801 Reported-by: Harshal Chhaya <harshal@gmail.com> Signed-off-by: Christian Lamparter <chunkeey@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
943c33996f
commit
5829656728
@ -661,11 +661,67 @@ void carl9170_tx_process_status(struct ar9170 *ar,
|
||||
}
|
||||
}
|
||||
|
||||
static void carl9170_tx_rate_tpc_chains(struct ar9170 *ar,
|
||||
struct ieee80211_tx_info *info, struct ieee80211_tx_rate *txrate,
|
||||
unsigned int *phyrate, unsigned int *tpc, unsigned int *chains)
|
||||
{
|
||||
struct ieee80211_rate *rate = NULL;
|
||||
u8 *txpower;
|
||||
unsigned int idx;
|
||||
|
||||
idx = txrate->idx;
|
||||
*tpc = 0;
|
||||
*phyrate = 0;
|
||||
|
||||
if (txrate->flags & IEEE80211_TX_RC_MCS) {
|
||||
if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
|
||||
/* +1 dBm for HT40 */
|
||||
*tpc += 2;
|
||||
|
||||
if (info->band == IEEE80211_BAND_2GHZ)
|
||||
txpower = ar->power_2G_ht40;
|
||||
else
|
||||
txpower = ar->power_5G_ht40;
|
||||
} else {
|
||||
if (info->band == IEEE80211_BAND_2GHZ)
|
||||
txpower = ar->power_2G_ht20;
|
||||
else
|
||||
txpower = ar->power_5G_ht20;
|
||||
}
|
||||
|
||||
*phyrate = txrate->idx;
|
||||
*tpc += txpower[idx & 7];
|
||||
} else {
|
||||
if (info->band == IEEE80211_BAND_2GHZ) {
|
||||
if (idx < 4)
|
||||
txpower = ar->power_2G_cck;
|
||||
else
|
||||
txpower = ar->power_2G_ofdm;
|
||||
} else {
|
||||
txpower = ar->power_5G_leg;
|
||||
idx += 4;
|
||||
}
|
||||
|
||||
rate = &__carl9170_ratetable[idx];
|
||||
*tpc += txpower[(rate->hw_value & 0x30) >> 4];
|
||||
*phyrate = rate->hw_value & 0xf;
|
||||
}
|
||||
|
||||
if (ar->eeprom.tx_mask == 1) {
|
||||
*chains = AR9170_TX_PHY_TXCHAIN_1;
|
||||
} else {
|
||||
if (!(txrate->flags & IEEE80211_TX_RC_MCS) &&
|
||||
rate && rate->bitrate >= 360)
|
||||
*chains = AR9170_TX_PHY_TXCHAIN_1;
|
||||
else
|
||||
*chains = AR9170_TX_PHY_TXCHAIN_2;
|
||||
}
|
||||
}
|
||||
|
||||
static __le32 carl9170_tx_physet(struct ar9170 *ar,
|
||||
struct ieee80211_tx_info *info, struct ieee80211_tx_rate *txrate)
|
||||
{
|
||||
struct ieee80211_rate *rate = NULL;
|
||||
u32 power, chains;
|
||||
unsigned int power = 0, chains = 0, phyrate = 0;
|
||||
__le32 tmp;
|
||||
|
||||
tmp = cpu_to_le32(0);
|
||||
@ -682,35 +738,12 @@ static __le32 carl9170_tx_physet(struct ar9170 *ar,
|
||||
tmp |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI);
|
||||
|
||||
if (txrate->flags & IEEE80211_TX_RC_MCS) {
|
||||
u32 r = txrate->idx;
|
||||
u8 *txpower;
|
||||
SET_VAL(AR9170_TX_PHY_MCS, phyrate, txrate->idx);
|
||||
|
||||
/* heavy clip control */
|
||||
tmp |= cpu_to_le32((r & 0x7) <<
|
||||
tmp |= cpu_to_le32((txrate->idx & 0x7) <<
|
||||
AR9170_TX_PHY_TX_HEAVY_CLIP_S);
|
||||
|
||||
if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
|
||||
if (info->band == IEEE80211_BAND_5GHZ)
|
||||
txpower = ar->power_5G_ht40;
|
||||
else
|
||||
txpower = ar->power_2G_ht40;
|
||||
} else {
|
||||
if (info->band == IEEE80211_BAND_5GHZ)
|
||||
txpower = ar->power_5G_ht20;
|
||||
else
|
||||
txpower = ar->power_2G_ht20;
|
||||
}
|
||||
|
||||
power = txpower[r & 7];
|
||||
|
||||
/* +1 dBm for HT40 */
|
||||
if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
|
||||
power += 2;
|
||||
|
||||
r <<= AR9170_TX_PHY_MCS_S;
|
||||
BUG_ON(r & ~AR9170_TX_PHY_MCS);
|
||||
|
||||
tmp |= cpu_to_le32(r & AR9170_TX_PHY_MCS);
|
||||
tmp |= cpu_to_le32(AR9170_TX_PHY_MOD_HT);
|
||||
|
||||
/*
|
||||
@ -720,34 +753,15 @@ static __le32 carl9170_tx_physet(struct ar9170 *ar,
|
||||
* tmp |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD);
|
||||
*/
|
||||
} else {
|
||||
u8 *txpower;
|
||||
u32 mod;
|
||||
u32 phyrate;
|
||||
u8 idx = txrate->idx;
|
||||
|
||||
if (info->band != IEEE80211_BAND_2GHZ) {
|
||||
idx += 4;
|
||||
txpower = ar->power_5G_leg;
|
||||
mod = AR9170_TX_PHY_MOD_OFDM;
|
||||
if (info->band == IEEE80211_BAND_2GHZ) {
|
||||
if (txrate->idx <= AR9170_TX_PHY_RATE_CCK_11M)
|
||||
tmp |= cpu_to_le32(AR9170_TX_PHY_MOD_CCK);
|
||||
else
|
||||
tmp |= cpu_to_le32(AR9170_TX_PHY_MOD_OFDM);
|
||||
} else {
|
||||
if (idx < 4) {
|
||||
txpower = ar->power_2G_cck;
|
||||
mod = AR9170_TX_PHY_MOD_CCK;
|
||||
} else {
|
||||
mod = AR9170_TX_PHY_MOD_OFDM;
|
||||
txpower = ar->power_2G_ofdm;
|
||||
}
|
||||
tmp |= cpu_to_le32(AR9170_TX_PHY_MOD_OFDM);
|
||||
}
|
||||
|
||||
rate = &__carl9170_ratetable[idx];
|
||||
|
||||
phyrate = rate->hw_value & 0xF;
|
||||
power = txpower[(rate->hw_value & 0x30) >> 4];
|
||||
phyrate <<= AR9170_TX_PHY_MCS_S;
|
||||
|
||||
tmp |= cpu_to_le32(mod);
|
||||
tmp |= cpu_to_le32(phyrate);
|
||||
|
||||
/*
|
||||
* short preamble seems to be broken too.
|
||||
*
|
||||
@ -755,23 +769,12 @@ static __le32 carl9170_tx_physet(struct ar9170 *ar,
|
||||
* tmp |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE);
|
||||
*/
|
||||
}
|
||||
power <<= AR9170_TX_PHY_TX_PWR_S;
|
||||
power &= AR9170_TX_PHY_TX_PWR;
|
||||
tmp |= cpu_to_le32(power);
|
||||
|
||||
/* set TX chains */
|
||||
if (ar->eeprom.tx_mask == 1) {
|
||||
chains = AR9170_TX_PHY_TXCHAIN_1;
|
||||
} else {
|
||||
chains = AR9170_TX_PHY_TXCHAIN_2;
|
||||
|
||||
/* >= 36M legacy OFDM - use only one chain */
|
||||
if (rate && rate->bitrate >= 360 &&
|
||||
!(txrate->flags & IEEE80211_TX_RC_MCS))
|
||||
chains = AR9170_TX_PHY_TXCHAIN_1;
|
||||
}
|
||||
tmp |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_S);
|
||||
carl9170_tx_rate_tpc_chains(ar, info, txrate,
|
||||
&phyrate, &power, &chains);
|
||||
|
||||
tmp |= cpu_to_le32(SET_CONSTVAL(AR9170_TX_PHY_MCS, phyrate));
|
||||
tmp |= cpu_to_le32(SET_CONSTVAL(AR9170_TX_PHY_TX_PWR, power));
|
||||
tmp |= cpu_to_le32(SET_CONSTVAL(AR9170_TX_PHY_TXCHAIN, chains));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@ -1444,8 +1447,10 @@ int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
|
||||
struct sk_buff *skb = NULL;
|
||||
struct carl9170_vif_info *cvif;
|
||||
struct ieee80211_tx_info *txinfo;
|
||||
struct ieee80211_tx_rate *rate;
|
||||
__le32 *data, *old = NULL;
|
||||
u32 word, off, addr, len;
|
||||
unsigned int plcp, power, chains;
|
||||
u32 word, ht1, off, addr, len;
|
||||
int i = 0, err = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
@ -1476,11 +1481,6 @@ int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
|
||||
}
|
||||
|
||||
txinfo = IEEE80211_SKB_CB(skb);
|
||||
if (txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS) {
|
||||
err = -EINVAL;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->beacon_lock);
|
||||
data = (__le32 *)skb->data;
|
||||
if (cvif->beacon)
|
||||
@ -1510,18 +1510,43 @@ int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
i = txinfo->control.rates[0].idx;
|
||||
if (txinfo->band != IEEE80211_BAND_2GHZ)
|
||||
i += 4;
|
||||
ht1 = AR9170_MAC_BCN_HT1_TX_ANT0;
|
||||
rate = &txinfo->control.rates[0];
|
||||
carl9170_tx_rate_tpc_chains(ar, txinfo, rate, &plcp, &power, &chains);
|
||||
if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) {
|
||||
if (plcp <= AR9170_TX_PHY_RATE_CCK_11M)
|
||||
plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
|
||||
else
|
||||
plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010;
|
||||
} else {
|
||||
ht1 |= AR9170_MAC_BCN_HT1_HT_EN;
|
||||
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
|
||||
plcp |= AR9170_MAC_BCN_HT2_SGI;
|
||||
|
||||
word = __carl9170_ratetable[i].hw_value & 0xf;
|
||||
if (i < 4)
|
||||
word |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
|
||||
else
|
||||
word |= ((skb->len + FCS_LEN) << 16) + 0x0010;
|
||||
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
|
||||
ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED;
|
||||
plcp |= AR9170_MAC_BCN_HT2_BW40;
|
||||
}
|
||||
if (rate->flags & IEEE80211_TX_RC_DUP_DATA) {
|
||||
ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP;
|
||||
plcp |= AR9170_MAC_BCN_HT2_BW40;
|
||||
}
|
||||
|
||||
SET_VAL(AR9170_MAC_BCN_HT2_LEN, plcp, skb->len + FCS_LEN);
|
||||
}
|
||||
|
||||
SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, ht1, 7);
|
||||
SET_VAL(AR9170_MAC_BCN_HT1_TPC, ht1, power);
|
||||
SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, ht1, chains);
|
||||
if (chains == AR9170_TX_PHY_TXCHAIN_2)
|
||||
ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1;
|
||||
|
||||
carl9170_async_regwrite_begin(ar);
|
||||
carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, word);
|
||||
carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT1, ht1);
|
||||
if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS))
|
||||
carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp);
|
||||
else
|
||||
carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT2, plcp);
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user