* [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, ¢ers);
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, ¢ers);
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, ¢ers);
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, ¢ers);
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.