ath9k: fix tx power reporting

Signed-off-by: Felix Fietkau <nbd@openwrt.org>

SVN-Revision: 43032
lede-17.01
Felix Fietkau 2014-10-22 16:26:56 +00:00
parent c14e0807bd
commit d9ea3d2aa8
11 changed files with 205 additions and 70 deletions

View File

@ -0,0 +1,43 @@
From: Felix Fietkau <nbd@openwrt.org>
Date: Wed, 22 Oct 2014 17:55:50 +0200
Subject: [PATCH] mac80211: add support for driver tx power reporting
The configured tx power is often limited by hardware capabilities,
channel settings, antenna configuration, etc.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2838,6 +2838,9 @@ enum ieee80211_roc_type {
* @get_expected_throughput: extract the expected throughput towards the
* specified station. The returned value is expressed in Kbps. It returns 0
* if the RC algorithm does not have proper data to provide.
+ *
+ * @get_txpower: get current maximum tx power (in dBm) based on configuration
+ * and hardware limits.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@@ -3039,6 +3042,8 @@ struct ieee80211_ops {
int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
u32 (*get_expected_throughput)(struct ieee80211_sta *sta);
+ int (*get_txpower)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ int *dbm);
};
/**
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2081,6 +2081,9 @@ static int ieee80211_get_tx_power(struct
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ if (local->ops->get_txpower)
+ return local->ops->get_txpower(&local->hw, &sdata->vif, dbm);
+
if (!local->use_chanctx)
*dbm = local->hw.conf.power_level;
else

View File

@ -0,0 +1,31 @@
From: Felix Fietkau <nbd@openwrt.org>
Date: Wed, 22 Oct 2014 18:16:14 +0200
Subject: [PATCH] ath9k_common: always update value in
ath9k_cmn_update_txpow
In some cases the limit may be the same as reg->power_limit, but the
actual value that the hardware uses is not up to date. In that case, a
wrong value for current tx power is tracked internally.
Fix this by unconditionally updating it.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -368,11 +368,11 @@ void ath9k_cmn_update_txpow(struct ath_h
{
struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
- if (reg->power_limit != new_txpow) {
+ if (reg->power_limit != new_txpow)
ath9k_hw_set_txpowerlimit(ah, new_txpow, false);
- /* read back in case value is clamped */
- *txpower = reg->max_power_level;
- }
+
+ /* read back in case value is clamped */
+ *txpower = reg->max_power_level;
}
EXPORT_SYMBOL(ath9k_cmn_update_txpow);

View File

@ -0,0 +1,118 @@
From: Felix Fietkau <nbd@openwrt.org>
Date: Wed, 22 Oct 2014 18:18:04 +0200
Subject: [PATCH] ath9k: add support for reporting tx power to mac80211
Track it per channel context instead of in the softc
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -347,6 +347,7 @@ struct ath_chanctx {
int flush_timeout;
u16 txpower;
+ u16 cur_txpower;
bool offchannel;
bool stopped;
bool active;
@@ -987,7 +988,6 @@ struct ath_softc {
u8 gtt_cnt;
u32 intrstatus;
u16 ps_flags; /* PS_* */
- u16 curtxpow;
bool ps_enabled;
bool ps_idle;
short nbcnvifs;
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -172,17 +172,20 @@ static void ath9k_reg_notifier(struct wi
ath_reg_notifier_apply(wiphy, request, reg);
/* Set tx power */
- if (ah->curchan) {
- sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power;
- ath9k_ps_wakeup(sc);
- ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false);
- sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
- /* synchronize DFS detector if regulatory domain changed */
- if (sc->dfs_detector != NULL)
- sc->dfs_detector->set_dfs_domain(sc->dfs_detector,
- request->dfs_region);
- ath9k_ps_restore(sc);
- }
+ if (!ah->curchan)
+ return;
+
+ sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power;
+ ath9k_ps_wakeup(sc);
+ ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false);
+ ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower,
+ sc->cur_chan->txpower,
+ &sc->cur_chan->cur_txpower);
+ /* synchronize DFS detector if regulatory domain changed */
+ if (sc->dfs_detector != NULL)
+ sc->dfs_detector->set_dfs_domain(sc->dfs_detector,
+ request->dfs_region);
+ ath9k_ps_restore(sc);
}
/*
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -233,8 +233,9 @@ static bool ath_complete_reset(struct at
ath9k_calculate_summary_state(sc, sc->cur_chan);
ath_startrecv(sc);
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
- sc->cur_chan->txpower, &sc->curtxpow);
+ ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower,
+ sc->cur_chan->txpower,
+ &sc->cur_chan->cur_txpower);
clear_bit(ATH_OP_HW_RESET, &common->op_flags);
if (!sc->cur_chan->offchannel && start) {
@@ -1471,8 +1472,9 @@ static int ath9k_config(struct ieee80211
if (changed & IEEE80211_CONF_CHANGE_POWER) {
ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level);
sc->cur_chan->txpower = 2 * conf->power_level;
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
- sc->cur_chan->txpower, &sc->curtxpow);
+ ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower,
+ sc->cur_chan->txpower,
+ &sc->cur_chan->cur_txpower);
}
mutex_unlock(&sc->mutex);
@@ -2594,6 +2596,24 @@ void ath9k_fill_chanctx_ops(void)
#endif
+static int ath9k_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ int *dbm)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_vif *avp = (void *)vif->drv_priv;
+
+ mutex_lock(&sc->mutex);
+ if (avp->chanctx)
+ *dbm = avp->chanctx->cur_txpower;
+ else
+ *dbm = sc->cur_chan->cur_txpower;
+ mutex_unlock(&sc->mutex);
+
+ *dbm /= 2;
+
+ return 0;
+}
+
struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
.start = ath9k_start,
@@ -2640,4 +2660,5 @@ struct ieee80211_ops ath9k_ops = {
#endif
.sw_scan_start = ath9k_sw_scan_start,
.sw_scan_complete = ath9k_sw_scan_complete,
+ .get_txpower = ath9k_get_txpower,
};

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -677,6 +677,7 @@ static const struct ieee80211_iface_limi
@@ -680,6 +680,7 @@ static const struct ieee80211_iface_limi
BIT(NL80211_IFTYPE_AP) },
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) },

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -986,23 +986,23 @@ static int __init ath9k_init(void)
@@ -989,23 +989,23 @@ static int __init ath9k_init(void)
{
int error;

View File

@ -1,33 +0,0 @@
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1754,6 +1754,7 @@ struct ieee80211_hw {
u8 max_tx_aggregation_subframes;
u8 offchannel_tx_hw_queue;
u8 radiotap_mcs_details;
+ s8 cur_power_level;
u16 radiotap_vht_details;
netdev_features_t netdev_features;
u8 uapsd_queues;
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2081,7 +2081,9 @@ static int ieee80211_get_tx_power(struct
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
- if (!local->use_chanctx)
+ if (local->hw.cur_power_level)
+ *dbm = local->hw.cur_power_level;
+ else if (!local->use_chanctx)
*dbm = local->hw.conf.power_level;
else
*dbm = sdata->vif.bss_conf.txpower;
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -157,6 +157,7 @@ static u32 ieee80211_hw_conf_chan(struct
if (local->hw.conf.power_level != power) {
changed |= IEEE80211_CONF_CHANGE_POWER;
+ local->hw.cur_power_level = power;
local->hw.conf.power_level = power;
}

View File

@ -1,24 +0,0 @@
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -326,8 +326,12 @@ static int ath_reset_internal(struct ath
sc->cur_chan->offchannel)
ath9k_mci_set_txpower(sc, true, false);
- if (!ath_complete_reset(sc, true))
+ if (!ath_complete_reset(sc, true)) {
r = -EIO;
+ goto out;
+ }
+
+ sc->hw->cur_power_level = sc->curtxpow / 2;
out:
spin_unlock_bh(&sc->sc_pcu_lock);
@@ -1473,6 +1477,7 @@ static int ath9k_config(struct ieee80211
sc->cur_chan->txpower = 2 * conf->power_level;
ath9k_cmn_update_txpow(ah, sc->curtxpow,
sc->cur_chan->txpower, &sc->curtxpow);
+ hw->cur_power_level = sc->curtxpow / 2;
}
mutex_unlock(&sc->mutex);

View File

@ -57,7 +57,7 @@
__NL80211_ATTR_AFTER_LAST,
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2091,6 +2091,19 @@ static int ieee80211_get_tx_power(struct
@@ -2092,6 +2092,19 @@ static int ieee80211_get_tx_power(struct
return 0;
}
@ -77,7 +77,7 @@
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
const u8 *addr)
{
@@ -3572,6 +3585,7 @@ const struct cfg80211_ops mac80211_confi
@@ -3573,6 +3586,7 @@ const struct cfg80211_ops mac80211_confi
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
@ -118,8 +118,8 @@
+
if (local->hw.conf.power_level != power) {
changed |= IEEE80211_CONF_CHANGE_POWER;
local->hw.cur_power_level = power;
@@ -586,6 +592,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
local->hw.conf.power_level = power;
@@ -585,6 +591,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
IEEE80211_RADIOTAP_MCS_HAVE_BW;
local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI |
IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -811,6 +811,9 @@ static inline int ath9k_dump_btcoex(stru
@@ -812,6 +812,9 @@ static inline int ath9k_dump_btcoex(stru
void ath_init_leds(struct ath_softc *sc);
void ath_deinit_leds(struct ath_softc *sc);
void ath_fill_led_pin(struct ath_softc *sc);
@ -10,7 +10,7 @@
#else
static inline void ath_init_leds(struct ath_softc *sc)
{
@@ -951,6 +954,13 @@ void ath_ant_comb_scan(struct ath_softc
@@ -952,6 +955,13 @@ void ath_ant_comb_scan(struct ath_softc
#define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */
@ -162,7 +162,7 @@
void ath_fill_led_pin(struct ath_softc *sc)
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -899,7 +899,7 @@ int ath9k_init_device(u16 devid, struct
@@ -902,7 +902,7 @@ int ath9k_init_device(u16 devid, struct
#ifdef CPTCFG_MAC80211_LEDS
/* must be initialized before ieee80211_register_hw */

View File

@ -125,7 +125,7 @@
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -535,6 +535,11 @@ irqreturn_t ath_isr(int irq, void *dev)
@@ -532,6 +532,11 @@ irqreturn_t ath_isr(int irq, void *dev)
ath9k_debug_sync_cause(sc, sync_cause);
status &= ah->imask; /* discard unasked-for bits */

View File

@ -55,7 +55,7 @@
ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -665,7 +665,8 @@ static void ath9k_init_txpower_limits(st
@@ -668,7 +668,8 @@ static void ath9k_init_txpower_limits(st
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ);
@ -65,7 +65,7 @@
}
static const struct ieee80211_iface_limit if_limits[] = {
@@ -856,6 +857,18 @@ static void ath9k_set_hw_capab(struct at
@@ -859,6 +860,18 @@ static void ath9k_set_hw_capab(struct at
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
}
@ -84,7 +84,7 @@
int ath9k_init_device(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops)
{
@@ -904,6 +917,8 @@ int ath9k_init_device(u16 devid, struct
@@ -907,6 +920,8 @@ int ath9k_init_device(u16 devid, struct
ARRAY_SIZE(ath9k_tpt_blink));
#endif