| 
					
				 | 
			
			
				@@ -0,0 +1,118 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+From: Felix Fietkau <[email protected]> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+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 <[email protected]> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- 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, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ }; 
			 |