linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/3] add TPC capability for AR9003 based chips
@ 2014-11-20 13:31 Lorenzo Bianconi
  2014-11-20 13:31 ` [RFC 1/3] ath9k: add chainmask parameter to ath9k_hw_get_scaled_power() Lorenzo Bianconi
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Lorenzo Bianconi @ 2014-11-20 13:31 UTC (permalink / raw)
  To: linux-wireless; +Cc: nbd, thomas, adrian

This patchset adds TPC capability to ath9k for AR9003 based chips. For the time
being some FCC checks are missing in ar9003_hw_init_txpower_stbc() and CDD mode
is not supported.
*[RFC 1/3]: add chainmask parameter to ath9k_hw_get_scaled_power() to compute
maximum TX power for different number of TX chains
*[RFC 2/3]: add TX power per-rate per-chain tables to cap TX power in TX
descriptor path
*[RFC 3/3]: cap per-packet TX power according to TX power per-rate per-chain
tables
This pachset is based on Adrian Chadd's hints
(https://www.mail-archive.com/ath9k-devel@lists.ath9k.org/msg10396.html)

Lorenzo Bianconi (3):
  ath9k: add chainmask parameter to ath9k_hw_get_scaled_power()
  ath9k: add TX power per-rate per-chain tables
  ath9k: add TPC capability to TX descriptor path

 drivers/net/wireless/ath/ath9k/ar9002_mac.c    |   8 +-
 drivers/net/wireless/ath/ath9k/ar9003_eeprom.c |  68 +++++-
 drivers/net/wireless/ath/ath9k/ar9003_eeprom.h |   5 +
 drivers/net/wireless/ath/ath9k/ar9003_mac.c    |   8 +-
 drivers/net/wireless/ath/ath9k/ar9003_phy.c    | 281 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/ath9k.h         |   1 +
 drivers/net/wireless/ath/ath9k/beacon.c        |   5 +-
 drivers/net/wireless/ath/ath9k/eeprom.c        |   4 +-
 drivers/net/wireless/ath/ath9k/eeprom.h        |   2 +-
 drivers/net/wireless/ath/ath9k/eeprom_9287.c   |   3 +-
 drivers/net/wireless/ath/ath9k/eeprom_def.c    |   3 +-
 drivers/net/wireless/ath/ath9k/hw.h            |   6 +
 drivers/net/wireless/ath/ath9k/mac.h           |   2 +-
 drivers/net/wireless/ath/ath9k/reg.h           |   2 +
 drivers/net/wireless/ath/ath9k/xmit.c          |  41 +++-
 15 files changed, 419 insertions(+), 20 deletions(-)

-- 
2.1.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC 1/3] ath9k: add chainmask parameter to ath9k_hw_get_scaled_power()
  2014-11-20 13:31 [RFC 0/3] add TPC capability for AR9003 based chips Lorenzo Bianconi
@ 2014-11-20 13:31 ` Lorenzo Bianconi
  2014-11-20 13:31 ` [RFC 2/3] ath9k: add TX power per-rate per-chain tables Lorenzo Bianconi
  2014-11-20 13:31 ` [RFC 3/3] ath9k: add TPC capability to TX descriptor path Lorenzo Bianconi
  2 siblings, 0 replies; 6+ messages in thread
From: Lorenzo Bianconi @ 2014-11-20 13:31 UTC (permalink / raw)
  To: linux-wireless; +Cc: nbd, thomas, adrian

Add chainmask parameter to ath9k_hw_get_scaled_power() in order to compute
maximum TX power per rate for different number of tx chains.
ath9k_hw_get_scaled_power() will be used during TPC TX power initialization

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
---
 drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 3 ++-
 drivers/net/wireless/ath/ath9k/eeprom.c        | 4 ++--
 drivers/net/wireless/ath/ath9k/eeprom.h        | 2 +-
 drivers/net/wireless/ath/ath9k/eeprom_9287.c   | 3 ++-
 drivers/net/wireless/ath/ath9k/eeprom_def.c    | 3 ++-
 5 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index e726e40..96d7538 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -5114,7 +5114,8 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
 
 	ath9k_hw_get_channel_centers(ah, chan, &centers);
 	scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit,
-						antenna_reduction);
+						antenna_reduction,
+						ah->txchainmask);
 
 	if (is2ghz) {
 		/* Setup for CTL modes */
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index 971d770..9304dca 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -308,7 +308,7 @@ u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
 }
 
 u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
-			      u8 antenna_reduction)
+			      u8 antenna_reduction, u8 chainmask)
 {
 	u16 reduction = antenna_reduction;
 
@@ -316,7 +316,7 @@ u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
 	 * Reduce scaled Power by number of chains active
 	 * to get the per chain tx power level.
 	 */
-	switch (ar5416_get_ntxchains(ah->txchainmask)) {
+	switch (ar5416_get_ntxchains(chainmask)) {
 	case 1:
 		break;
 	case 2:
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 40d4f62..f83bc0f 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -684,7 +684,7 @@ void ath9k_hw_get_target_powers(struct ath_hw *ah,
 u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
 				bool is2GHz, int num_band_edges);
 u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
-			      u8 antenna_reduction);
+			      u8 antenna_reduction, u8 chainmask);
 void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah);
 int ath9k_hw_eeprom_init(struct ath_hw *ah);
 
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 5ba1385..beb5b6b 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -584,7 +584,8 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
 
 	ath9k_hw_get_channel_centers(ah, chan, &centers);
 	scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit,
-						antenna_reduction);
+						antenna_reduction,
+						ah->txchainmask);
 
 	/*
 	 * Get TX power from EEPROM.
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 122b846..8de2874 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -1009,7 +1009,8 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
 	ath9k_hw_get_channel_centers(ah, chan, &centers);
 
 	scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit,
-						antenna_reduction);
+						antenna_reduction,
+						ah->txchainmask);
 
 	if (IS_CHAN_2GHZ(chan)) {
 		numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 2/3] ath9k: add TX power per-rate per-chain tables
  2014-11-20 13:31 [RFC 0/3] add TPC capability for AR9003 based chips Lorenzo Bianconi
  2014-11-20 13:31 ` [RFC 1/3] ath9k: add chainmask parameter to ath9k_hw_get_scaled_power() Lorenzo Bianconi
@ 2014-11-20 13:31 ` Lorenzo Bianconi
  2014-11-20 14:49   ` Felix Fietkau
  2014-11-20 13:31 ` [RFC 3/3] ath9k: add TPC capability to TX descriptor path Lorenzo Bianconi
  2 siblings, 1 reply; 6+ messages in thread
From: Lorenzo Bianconi @ 2014-11-20 13:31 UTC (permalink / raw)
  To: linux-wireless; +Cc: nbd, thomas, adrian

Add TX power per-rate per-chain tables for different MIMO modes (e.g STBC) in
order to cap the maximum TX power value per-rate in the TX descriptor path.
Cap TX power for self generated frames (ACK, RTS/CTS).
Currently TPC is supported just by AR9003 based chips

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
---
 drivers/net/wireless/ath/ath9k/ar9003_eeprom.c |  67 +++++-
 drivers/net/wireless/ath/ath9k/ar9003_eeprom.h |   5 +
 drivers/net/wireless/ath/ath9k/ar9003_phy.c    | 281 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/hw.h            |   6 +
 drivers/net/wireless/ath/ath9k/reg.h           |   2 +
 5 files changed, 358 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 96d7538..8acabcd 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -4377,6 +4377,25 @@ static u8 ar9003_hw_eeprom_get_cck_tgt_pwr(struct ath_hw *ah,
 						 targetPowerArray, numPiers);
 }
 
+static void ar9003_hw_selfgen_tpc_txpower(struct ath_hw *ah,
+					  struct ath9k_channel *chan,
+					  u8 *pwr_array)
+{
+	u32 val;
+
+	/* target power values for self generated frames (ACK,RTS/CTS) */
+	if (IS_CHAN_2GHZ(chan)) {
+		val = SM(pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_ACK) |
+		      SM(pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_CTS) |
+		      SM(0x3f, AR_TPC_CHIRP) | SM(0x3f, AR_TPC_RPT);
+	} else {
+		val = SM(pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_ACK) |
+		      SM(pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_CTS) |
+		      SM(0x3f, AR_TPC_CHIRP) | SM(0x3f, AR_TPC_RPT);
+	}
+	REG_WRITE(ah, AR_TPC, val);
+}
+
 /* Set tx power registers to array of values passed in */
 static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
 {
@@ -5089,7 +5108,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
 					       struct ath9k_channel *chan,
 					       u8 *pPwrArray, u16 cfgCtl,
 					       u8 antenna_reduction,
-					       u16 powerLimit)
+					       u16 powerLimit, u8 chainmask)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep;
@@ -5115,7 +5134,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
 	ath9k_hw_get_channel_centers(ah, chan, &centers);
 	scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit,
 						antenna_reduction,
-						ah->txchainmask);
+						chainmask);
 
 	if (is2ghz) {
 		/* Setup for CTL modes */
@@ -5313,6 +5332,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
 	struct ar9300_modal_eep_header *modal_hdr;
 	u8 targetPowerValT2[ar9300RateSize];
 	u8 target_power_val_t2_eep[ar9300RateSize];
+	u8 targetPowerValT2_tpc[ar9300RateSize];
 	unsigned int i = 0, paprd_scale_factor = 0;
 	u8 pwr_idx, min_pwridx = 0;
 
@@ -5359,10 +5379,13 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
 		       sizeof(targetPowerValT2));
 	}
 
+	memcpy(targetPowerValT2_tpc, targetPowerValT2,
+	       sizeof(targetPowerValT2));
+
 	ar9003_hw_set_power_per_rate_table(ah, chan,
 					   targetPowerValT2, cfgCtl,
 					   twiceAntennaReduction,
-					   powerLimit);
+					   powerLimit, ah->txchainmask);
 
 	if (ar9003_is_paprd_enabled(ah)) {
 		for (i = 0; i < ar9300RateSize; i++) {
@@ -5397,6 +5420,44 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
 	ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
 	ar9003_hw_calibration_apply(ah, chan->channel);
 	ar9003_paprd_set_txpower(ah, chan, targetPowerValT2);
+
+	ar9003_hw_selfgen_tpc_txpower(ah, chan, targetPowerValT2);
+
+	/* TPC initializations */
+	if (ah->tpc_enabled) {
+		u32 val;
+		u8 chainmask[] = {
+			AR9300_1_CHAINMASK,
+			AR9300_2LOHI_CHAINMASK,
+			AR9300_3_CHAINMASK
+		};
+		for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+			memcpy(targetPowerValT2, targetPowerValT2_tpc,
+			       sizeof(targetPowerValT2));
+			ar9003_hw_set_power_per_rate_table(ah, chan,
+							   targetPowerValT2,
+							   cfgCtl,
+							   twiceAntennaReduction,
+							   powerLimit,
+							   chainmask[i]);
+			ar9003_hw_init_rate_txpower(ah, targetPowerValT2,
+						    chan, chainmask[i]);
+		}
+		/* Enable TPC */
+		REG_WRITE(ah, AR_PHY_PWRTX_MAX,
+			  AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
+		/* Disable per chain power reduction */
+		val = REG_READ(ah, AR_PHY_POWER_TX_SUB);
+		if (AR_SREV_9340(ah))
+			REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
+				  val & 0xFFFFFFC0);
+		else
+			REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
+				  val & 0xFFFFF000);
+	} else {
+		/* Disable TPC */
+		REG_WRITE(ah, AR_PHY_PWRTX_MAX, 0);
+	}
 }
 
 static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
index 694ca2e..02bcc85 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
@@ -46,6 +46,11 @@
 #define AR9300_ANT_16S               25
 #define AR9300_FUTURE_MODAL_SZ       6
 
+#define AR9300_1_CHAINMASK		1
+#define AR9300_2LOMID_CHAINMASK		3
+#define AR9300_2LOHI_CHAINMASK		5
+#define AR9300_3_CHAINMASK		7
+
 #define AR9300_PAPRD_RATE_MASK		0x01ffffff
 #define AR9300_PAPRD_SCALE_1		0x0e000000
 #define AR9300_PAPRD_SCALE_1_S		25
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 2df6d2e..9f1445e 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -18,6 +18,21 @@
 #include "hw.h"
 #include "ar9003_phy.h"
 
+#define AR9300_OFDM_RATES	8
+#define AR9300_HT_SS_RATES	8
+#define AR9300_HT_DS_RATES	8
+#define AR9300_HT_TS_RATES	8
+
+#define AR9300_11NA_OFDM_SHIFT		0
+#define AR9300_11NA_HT_SS_SHIFT		8
+#define AR9300_11NA_HT_DS_SHIFT		16
+#define AR9300_11NA_HT_TS_SHIFT		24
+
+#define AR9300_11NG_OFDM_SHIFT		4
+#define AR9300_11NG_HT_SS_SHIFT		12
+#define AR9300_11NG_HT_DS_SHIFT		20
+#define AR9300_11NG_HT_TS_SHIFT		28
+
 static const int firstep_table[] =
 /* level:  0   1   2   3   4   5   6   7   8  */
 	{ -4, -2,  0,  2,  4,  6,  8, 10, 12 }; /* lvl 0-8, default 2 */
@@ -40,6 +55,71 @@ static const int m2ThreshLowExt_off = 127;
 static const int m1ThreshExt_off = 127;
 static const int m2ThreshExt_off = 127;
 
+static const u8 ofdm2pwr[] = {
+	ALL_TARGET_LEGACY_6_24,
+	ALL_TARGET_LEGACY_6_24,
+	ALL_TARGET_LEGACY_6_24,
+	ALL_TARGET_LEGACY_6_24,
+	ALL_TARGET_LEGACY_6_24,
+	ALL_TARGET_LEGACY_36,
+	ALL_TARGET_LEGACY_48,
+	ALL_TARGET_LEGACY_54
+};
+
+static const u8 mcs2pwr_ht20[] = {
+	ALL_TARGET_HT20_0_8_16,
+	ALL_TARGET_HT20_1_3_9_11_17_19,
+	ALL_TARGET_HT20_1_3_9_11_17_19,
+	ALL_TARGET_HT20_1_3_9_11_17_19,
+	ALL_TARGET_HT20_4,
+	ALL_TARGET_HT20_5,
+	ALL_TARGET_HT20_6,
+	ALL_TARGET_HT20_7,
+	ALL_TARGET_HT20_0_8_16,
+	ALL_TARGET_HT20_1_3_9_11_17_19,
+	ALL_TARGET_HT20_1_3_9_11_17_19,
+	ALL_TARGET_HT20_1_3_9_11_17_19,
+	ALL_TARGET_HT20_12,
+	ALL_TARGET_HT20_13,
+	ALL_TARGET_HT20_14,
+	ALL_TARGET_HT20_15,
+	ALL_TARGET_HT20_0_8_16,
+	ALL_TARGET_HT20_1_3_9_11_17_19,
+	ALL_TARGET_HT20_1_3_9_11_17_19,
+	ALL_TARGET_HT20_1_3_9_11_17_19,
+	ALL_TARGET_HT20_20,
+	ALL_TARGET_HT20_21,
+	ALL_TARGET_HT20_22,
+	ALL_TARGET_HT20_23
+};
+
+static const u8 mcs2pwr_ht40[] = {
+	ALL_TARGET_HT40_0_8_16,
+	ALL_TARGET_HT40_1_3_9_11_17_19,
+	ALL_TARGET_HT40_1_3_9_11_17_19,
+	ALL_TARGET_HT40_1_3_9_11_17_19,
+	ALL_TARGET_HT40_4,
+	ALL_TARGET_HT40_5,
+	ALL_TARGET_HT40_6,
+	ALL_TARGET_HT40_7,
+	ALL_TARGET_HT40_0_8_16,
+	ALL_TARGET_HT40_1_3_9_11_17_19,
+	ALL_TARGET_HT40_1_3_9_11_17_19,
+	ALL_TARGET_HT40_1_3_9_11_17_19,
+	ALL_TARGET_HT40_12,
+	ALL_TARGET_HT40_13,
+	ALL_TARGET_HT40_14,
+	ALL_TARGET_HT40_15,
+	ALL_TARGET_HT40_0_8_16,
+	ALL_TARGET_HT40_1_3_9_11_17_19,
+	ALL_TARGET_HT40_1_3_9_11_17_19,
+	ALL_TARGET_HT40_1_3_9_11_17_19,
+	ALL_TARGET_HT40_20,
+	ALL_TARGET_HT40_21,
+	ALL_TARGET_HT40_22,
+	ALL_TARGET_HT40_23,
+};
+
 /**
  * ar9003_hw_set_channel - set channel on single-chip device
  * @ah: atheros hardware structure
@@ -1799,6 +1879,207 @@ static void ar9003_hw_tx99_set_txpower(struct ath_hw *ah, u8 txpower)
 		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_14],  0));
 }
 
+static void ar9003_hw_init_txpower_cck(struct ath_hw *ah, u8 *rate_array)
+{
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		ah->tx_power[0][i] = rate_array[ALL_TARGET_LEGACY_1L_5L];
+		ah->tx_power[1][i] = rate_array[ALL_TARGET_LEGACY_1L_5L];
+		ah->tx_power[2][i] = min(rate_array[ALL_TARGET_LEGACY_1L_5L],
+					 rate_array[ALL_TARGET_LEGACY_5S]);
+		ah->tx_power[3][i] = min(rate_array[ALL_TARGET_LEGACY_11L],
+					 rate_array[ALL_TARGET_LEGACY_11S]);
+	}
+}
+
+static void ar9003_hw_init_txpower_ofdm(struct ath_hw *ah, u8 *rate_array,
+					int offset, u8 chainmask)
+{
+	int i, j;
+
+	for (i = offset; i < offset + AR9300_OFDM_RATES; i++) {
+		/* OFDM rate to power table idx */
+		j = ofdm2pwr[i - offset];
+		switch (chainmask) {
+		case AR9300_1_CHAINMASK:
+			ah->tx_power[i][0] = rate_array[j];
+			break;
+		case AR9300_2LOMID_CHAINMASK:
+		case AR9300_2LOHI_CHAINMASK:
+			ah->tx_power[i][1] = rate_array[j];
+			break;
+		case AR9300_3_CHAINMASK:
+			ah->tx_power[i][2] = rate_array[j];
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static void ar9003_hw_init_txpower_ht(struct ath_hw *ah, u8 *rate_array,
+				      int ss_offset, int ds_offset,
+				      int ts_offset, u8 chainmask, bool is_40)
+{
+	int i, j, mcs_idx = 0;
+	const u8 *mcs2pwr = (is_40) ? mcs2pwr_ht40 : mcs2pwr_ht20;
+
+	for (i = ss_offset; i < ss_offset + AR9300_HT_SS_RATES; i++) {
+		j = mcs2pwr[mcs_idx];
+		switch (chainmask) {
+		case AR9300_1_CHAINMASK:
+			ah->tx_power[i][0] = rate_array[j];
+			break;
+		case AR9300_2LOMID_CHAINMASK:
+		case AR9300_2LOHI_CHAINMASK:
+			ah->tx_power[i][1] = rate_array[j];
+			break;
+		case AR9300_3_CHAINMASK:
+			ah->tx_power[i][2] = rate_array[j];
+			break;
+		default:
+			break;
+		}
+		mcs_idx++;
+	}
+
+	for (i = ds_offset; i < ds_offset + AR9300_HT_DS_RATES; i++) {
+		j = mcs2pwr[mcs_idx];
+		switch (chainmask) {
+		case AR9300_1_CHAINMASK:
+			ah->tx_power[i][0] = rate_array[j];
+			break;
+		case AR9300_2LOMID_CHAINMASK:
+		case AR9300_2LOHI_CHAINMASK:
+			ah->tx_power[i][1] = rate_array[j];
+			break;
+		case AR9300_3_CHAINMASK:
+			ah->tx_power[i][2] = rate_array[j];
+			break;
+		default:
+			break;
+		}
+		mcs_idx++;
+	}
+
+	for (i = ts_offset; i < ts_offset + AR9300_HT_TS_RATES; i++) {
+		j = mcs2pwr[mcs_idx];
+		switch (chainmask) {
+		case AR9300_1_CHAINMASK:
+			ah->tx_power[i][0] = rate_array[j];
+			break;
+		case AR9300_2LOMID_CHAINMASK:
+		case AR9300_2LOHI_CHAINMASK:
+			ah->tx_power[i][1] = rate_array[j];
+			break;
+		case AR9300_3_CHAINMASK:
+			ah->tx_power[i][2] = rate_array[j];
+			break;
+		default:
+			break;
+		}
+		mcs_idx++;
+	}
+}
+
+static void ar9003_hw_init_txpower_stbc(struct ath_hw *ah, u8 chainmask,
+					int ss_offset, int ds_offset,
+					int ts_offset)
+{
+	int i;
+
+	for (i = ss_offset; i < ss_offset + AR9300_HT_SS_RATES; i++) {
+		switch (chainmask) {
+		case AR9300_1_CHAINMASK:
+			ah->tx_power_stbc[i][0] = ah->tx_power[i][0];
+			break;
+		case AR9300_2LOMID_CHAINMASK:
+		case AR9300_2LOHI_CHAINMASK:
+			ah->tx_power_stbc[i][1] = ah->tx_power[i][1];
+			break;
+		case AR9300_3_CHAINMASK:
+			ah->tx_power_stbc[i][2] = ah->tx_power[i][2];
+			break;
+		default:
+			break;
+		}
+	}
+
+	for (i = ds_offset; i < ds_offset + AR9300_HT_DS_RATES; i++) {
+		switch (chainmask) {
+		case AR9300_1_CHAINMASK:
+			ah->tx_power_stbc[i][0] = ah->tx_power[i][0];
+			break;
+		case AR9300_2LOMID_CHAINMASK:
+		case AR9300_2LOHI_CHAINMASK:
+			ah->tx_power_stbc[i][1] = ah->tx_power[i][1];
+			break;
+		case AR9300_3_CHAINMASK:
+			ah->tx_power_stbc[i][2] = ah->tx_power[i][2];
+			break;
+		default:
+			break;
+		}
+	}
+
+	for (i = ts_offset; i < ts_offset + AR9300_HT_TS_RATES; i++) {
+		switch (chainmask) {
+		case AR9300_1_CHAINMASK:
+			ah->tx_power_stbc[i][0] = ah->tx_power[i][0];
+			break;
+		case AR9300_2LOMID_CHAINMASK:
+		case AR9300_2LOHI_CHAINMASK:
+			ah->tx_power_stbc[i][1] = ah->tx_power[i][1];
+			break;
+		case AR9300_3_CHAINMASK:
+			ah->tx_power_stbc[i][2] = ah->tx_power[i][2];
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array,
+				 struct ath9k_channel *chan, u8 chainmask)
+{
+	if (IS_CHAN_5GHZ(chan)) {
+		ar9003_hw_init_txpower_ofdm(ah, rate_array,
+					    AR9300_11NA_OFDM_SHIFT,
+					    chainmask);
+		if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) {
+			ar9003_hw_init_txpower_ht(ah, rate_array,
+						  AR9300_11NA_HT_SS_SHIFT,
+						  AR9300_11NA_HT_DS_SHIFT,
+						  AR9300_11NA_HT_TS_SHIFT,
+						  IS_CHAN_HT40(chan),
+						  chainmask);
+			ar9003_hw_init_txpower_stbc(ah, chainmask,
+						    AR9300_11NA_HT_SS_SHIFT,
+						    AR9300_11NA_HT_DS_SHIFT,
+						    AR9300_11NA_HT_TS_SHIFT);
+		}
+	} else {
+		ar9003_hw_init_txpower_cck(ah, rate_array);
+		ar9003_hw_init_txpower_ofdm(ah, rate_array,
+					    AR9300_11NG_OFDM_SHIFT,
+					    chainmask);
+		if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) {
+			ar9003_hw_init_txpower_ht(ah, rate_array,
+						  AR9300_11NG_HT_SS_SHIFT,
+						  AR9300_11NG_HT_DS_SHIFT,
+						  AR9300_11NG_HT_TS_SHIFT,
+						  IS_CHAN_HT40(chan),
+						  chainmask);
+			ar9003_hw_init_txpower_stbc(ah, chainmask,
+						    AR9300_11NG_HT_SS_SHIFT,
+						    AR9300_11NG_HT_DS_SHIFT,
+						    AR9300_11NG_HT_TS_SHIFT);
+		}
+	}
+}
+
 void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
 {
 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 4cf9e0a..3fcfdaf 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -940,6 +940,10 @@ struct ath_hw {
 	const struct firmware *eeprom_blob;
 
 	struct ath_dynack dynack;
+
+	bool tpc_enabled;
+	u8 tx_power[Ar5416RateSize][AR5416_MAX_CHAINS];
+	u8 tx_power_stbc[Ar5416RateSize][AR5416_MAX_CHAINS];
 };
 
 struct ath_bus_ops {
@@ -1080,6 +1084,8 @@ int ar9003_paprd_init_table(struct ath_hw *ah);
 bool ar9003_paprd_is_done(struct ath_hw *ah);
 bool ar9003_is_paprd_enabled(struct ath_hw *ah);
 void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
+void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array,
+				 struct ath9k_channel *chan, u8 chainmask);
 
 /* Hardware family op attach helpers */
 int ar5008_hw_attach_phy_ops(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index ced36b4..fb11a91 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -1724,6 +1724,8 @@ enum {
 #define AR_TPC_CTS_S           8
 #define AR_TPC_CHIRP           0x003f0000
 #define AR_TPC_CHIRP_S         16
+#define AR_TPC_RPT	       0x3f000000
+#define AR_TPC_RPT_S	       24
 
 #define AR_QUIET1          0x80fc
 #define AR_QUIET1_NEXT_QUIET_S         0
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 3/3] ath9k: add TPC capability to TX descriptor path
  2014-11-20 13:31 [RFC 0/3] add TPC capability for AR9003 based chips Lorenzo Bianconi
  2014-11-20 13:31 ` [RFC 1/3] ath9k: add chainmask parameter to ath9k_hw_get_scaled_power() Lorenzo Bianconi
  2014-11-20 13:31 ` [RFC 2/3] ath9k: add TX power per-rate per-chain tables Lorenzo Bianconi
@ 2014-11-20 13:31 ` Lorenzo Bianconi
  2 siblings, 0 replies; 6+ messages in thread
From: Lorenzo Bianconi @ 2014-11-20 13:31 UTC (permalink / raw)
  To: linux-wireless; +Cc: nbd, thomas, adrian

Add TPC capability to TX descriptor path. Cap per-packet TX power according to
TX power per-rate per-chain tables. Currently TPC is supported just by AR9003
based chips

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
---
 drivers/net/wireless/ath/ath9k/ar9002_mac.c |  8 +++---
 drivers/net/wireless/ath/ath9k/ar9003_mac.c |  8 +++---
 drivers/net/wireless/ath/ath9k/ath9k.h      |  1 +
 drivers/net/wireless/ath/ath9k/beacon.c     |  5 ++--
 drivers/net/wireless/ath/ath9k/mac.h        |  2 +-
 drivers/net/wireless/ath/ath9k/xmit.c       | 41 ++++++++++++++++++++++++++++-
 6 files changed, 53 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 2a93519..f816909 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -281,7 +281,7 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
 
 	ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen)
 		| (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
-		| SM(i->txpower, AR_XmitPower0)
+		| SM(i->txpower[0], AR_XmitPower0)
 		| (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
 		| (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
 		| (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
@@ -307,9 +307,9 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
 		| set11nRateFlags(i->rates, 3)
 		| SM(i->rtscts_rate, AR_RTSCTSRate);
 
-	ACCESS_ONCE(ads->ds_ctl9) = SM(i->txpower, AR_XmitPower1);
-	ACCESS_ONCE(ads->ds_ctl10) = SM(i->txpower, AR_XmitPower2);
-	ACCESS_ONCE(ads->ds_ctl11) = SM(i->txpower, AR_XmitPower3);
+	ACCESS_ONCE(ads->ds_ctl9) = SM(i->txpower[1], AR_XmitPower1);
+	ACCESS_ONCE(ads->ds_ctl10) = SM(i->txpower[2], AR_XmitPower2);
+	ACCESS_ONCE(ads->ds_ctl11) = SM(i->txpower[3], AR_XmitPower3);
 }
 
 static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 057b165..da84b70 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -101,7 +101,7 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
 
 	ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen)
 		| (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
-		| SM(i->txpower, AR_XmitPower0)
+		| SM(i->txpower[0], AR_XmitPower0)
 		| (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
 		| (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
 		| (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0)
@@ -152,9 +152,9 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
 
 	ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding;
 
-	ACCESS_ONCE(ads->ctl20) = SM(i->txpower, AR_XmitPower1);
-	ACCESS_ONCE(ads->ctl21) = SM(i->txpower, AR_XmitPower2);
-	ACCESS_ONCE(ads->ctl22) = SM(i->txpower, AR_XmitPower3);
+	ACCESS_ONCE(ads->ctl20) = SM(i->txpower[1], AR_XmitPower1);
+	ACCESS_ONCE(ads->ctl21) = SM(i->txpower[2], AR_XmitPower2);
+	ACCESS_ONCE(ads->ctl22) = SM(i->txpower[3], AR_XmitPower3);
 }
 
 static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index abe8bd6..1a9fe09 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -189,6 +189,7 @@ struct ath_frame_info {
 	u8 rtscts_rate;
 	u8 retries : 7;
 	u8 baw_tracked : 1;
+	u8 tx_power;
 };
 
 struct ath_rxbuf {
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index ecb783b..cb366ad 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -78,7 +78,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
 	struct ath_tx_info info;
 	struct ieee80211_supported_band *sband;
 	u8 chainmask = ah->txchainmask;
-	u8 rate = 0;
+	u8 i, rate = 0;
 
 	sband = &common->sbands[sc->cur_chandef.chan->band];
 	rate = sband->bitrates[rateidx].hw_value;
@@ -88,7 +88,8 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
 	memset(&info, 0, sizeof(info));
 	info.pkt_len = skb->len + FCS_LEN;
 	info.type = ATH9K_PKT_TYPE_BEACON;
-	info.txpower = MAX_RATE_POWER;
+	for (i = 0; i < 4; i++)
+		info.txpower[i] = MAX_RATE_POWER;
 	info.keyix = ATH9K_TXKEYIX_INVALID;
 	info.keytype = ATH9K_KEY_TYPE_CLEAR;
 	info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK;
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index aa69cea..e55fa11 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -704,7 +704,7 @@ struct ath_tx_info {
 	enum ath9k_pkt_type type;
 	enum ath9k_key_type keytype;
 	u8 keyix;
-	u8 txpower;
+	u8 txpower[4];
 };
 
 struct ath_hw;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index d6e54a3..f0e18d9 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1096,6 +1096,39 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop)
 	}
 }
 
+static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf,
+			       u8 rateidx, u8 chainmask)
+{
+	u8 max_power;
+	struct ath_hw *ah = sc->sc_ah;
+
+	if (sc->tx99_state)
+		return MAX_RATE_POWER;
+
+	if (!AR_SREV_9300_20_OR_LATER(ah)) {
+		/* ar9002 is not sipported for the moment */
+		return MAX_RATE_POWER;
+	}
+
+	if (!bf->bf_state.bfs_paprd) {
+		struct sk_buff *skb = bf->bf_mpdu;
+		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+		struct ath_frame_info *fi = get_frame_info(skb);
+		u8 nchain = ar5416_get_ntxchains(chainmask);
+
+		if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC))
+			max_power = min(ah->tx_power_stbc[rateidx][nchain - 1],
+					fi->tx_power);
+		else
+			max_power = min(ah->tx_power[rateidx][nchain - 1],
+					fi->tx_power);
+	} else {
+		max_power = ah->paprd_training_power;
+	}
+
+	return max_power;
+}
+
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
 			     struct ath_tx_info *info, int len, bool rts)
 {
@@ -1166,6 +1199,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
 				 is_40, is_sgi, is_sp);
 			if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
 				info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC;
+
+			info->txpower[i] = ath_get_rate_txpower(sc, bf, rix,
+							info->rates[i].ChSel);
 			continue;
 		}
 
@@ -1193,6 +1229,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
 
 		info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
 			phy, rate->bitrate * 100, len, rix, is_sp);
+
+		info->txpower[i] = ath_get_rate_txpower(sc, bf, rix,
+							info->rates[i].ChSel);
 	}
 
 	/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
@@ -1239,7 +1278,6 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
 	memset(&info, 0, sizeof(info));
 	info.is_first = true;
 	info.is_last = true;
-	info.txpower = MAX_RATE_POWER;
 	info.qcu = txq->axq_qnum;
 
 	while (bf) {
@@ -2063,6 +2101,7 @@ static void setup_frame_info(struct ieee80211_hw *hw,
 		fi->keyix = ATH9K_TXKEYIX_INVALID;
 	fi->keytype = keytype;
 	fi->framelen = framelen;
+	fi->tx_power = MAX_RATE_POWER;
 
 	if (!rate)
 		return;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [RFC 2/3] ath9k: add TX power per-rate per-chain tables
  2014-11-20 13:31 ` [RFC 2/3] ath9k: add TX power per-rate per-chain tables Lorenzo Bianconi
@ 2014-11-20 14:49   ` Felix Fietkau
  2014-11-21 13:07     ` Lorenzo Bianconi
  0 siblings, 1 reply; 6+ messages in thread
From: Felix Fietkau @ 2014-11-20 14:49 UTC (permalink / raw)
  To: Lorenzo Bianconi, linux-wireless; +Cc: thomas, adrian

On 2014-11-20 14:31, Lorenzo Bianconi wrote:
> Add TX power per-rate per-chain tables for different MIMO modes (e.g STBC) in
> order to cap the maximum TX power value per-rate in the TX descriptor path.
> Cap TX power for self generated frames (ACK, RTS/CTS).
> Currently TPC is supported just by AR9003 based chips
> 
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
I think you should make the ah->txpower array one-dimensional and store
it for the current chainmask only - this will simplify the code.
The chainmask cannot be changed while the interface is up, so there's no
need to make this dynamically switchable.

- Felix

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC 2/3] ath9k: add TX power per-rate per-chain tables
  2014-11-20 14:49   ` Felix Fietkau
@ 2014-11-21 13:07     ` Lorenzo Bianconi
  0 siblings, 0 replies; 6+ messages in thread
From: Lorenzo Bianconi @ 2014-11-21 13:07 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, Thomas Hühn, adrian

> On 2014-11-20 14:31, Lorenzo Bianconi wrote:
>> Add TX power per-rate per-chain tables for different MIMO modes (e.g STBC) in
>> order to cap the maximum TX power value per-rate in the TX descriptor path.
>> Cap TX power for self generated frames (ACK, RTS/CTS).
>> Currently TPC is supported just by AR9003 based chips
>>
>> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
> I think you should make the ah->txpower array one-dimensional and store
> it for the current chainmask only - this will simplify the code.
> The chainmask cannot be changed while the interface is up, so there's no
> need to make this dynamically switchable.
>
> - Felix

Ack. In this way I can drop patch 1/3 and simplify the code. Thx :)

Lorenzo

-- 
UNIX is Sexy: who | grep -i blonde | talk; cd ~; wine; talk; touch;
unzip; touch; strip; gasp; finger; gasp; mount; fsck; more; yes; gasp;
umount; make clean; sleep

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-11-21 13:14 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-20 13:31 [RFC 0/3] add TPC capability for AR9003 based chips Lorenzo Bianconi
2014-11-20 13:31 ` [RFC 1/3] ath9k: add chainmask parameter to ath9k_hw_get_scaled_power() Lorenzo Bianconi
2014-11-20 13:31 ` [RFC 2/3] ath9k: add TX power per-rate per-chain tables Lorenzo Bianconi
2014-11-20 14:49   ` Felix Fietkau
2014-11-21 13:07     ` Lorenzo Bianconi
2014-11-20 13:31 ` [RFC 3/3] ath9k: add TPC capability to TX descriptor path Lorenzo Bianconi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).