2010-12-12 13:34:46

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 1/7] ath9k_hw: initialize ah->slottime

(u32) -1 is not particularly useful as a slottime default, so even though
the ath9k_hw default should never get used, it's better to pick something
sane here.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/hw.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index d44f74e..856a76e 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -408,7 +408,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
AR_STA_ID1_CRPT_MIC_ENABLE |
AR_STA_ID1_MCAST_KSRCH;
ah->enable_32kHz_clock = DONT_USE_32KHZ;
- ah->slottime = (u32) -1;
+ ah->slottime = 20;
ah->globaltxtimeout = (u32) -1;
ah->power_mode = ATH9K_PM_UNDEFINED;
}
--
1.7.3.2



2010-12-12 13:34:47

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 7/7] ath9k_hw: update AR9003 initvals to improve carrier leak calibration/correction

Signed-off-by: Felix Fietkau <[email protected]>
---
.../net/wireless/ath/ath9k/ar9003_2p2_initvals.h | 100 ++++++++++----------
1 files changed, 50 insertions(+), 50 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index ec50ca1..81f9cf2 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -34,9 +34,9 @@ static const u32 ar9300_2p2_radio_postamble[][5] = {

static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000a2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
+ {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
+ {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
{0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@@ -56,21 +56,21 @@ static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
- {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
- {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
- {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
- {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
- {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
- {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
- {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
- {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
- {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
- {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
@@ -88,44 +88,44 @@ static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
- {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
- {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
- {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
- {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
- {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
- {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
- {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
- {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
- {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
- {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
- {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
- {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
- {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
- {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
- {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
- {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
- {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+ {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+ {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+ {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+ {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+ {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+ {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000b2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
+ {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
+ {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
{0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
+ {0x0000c2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
+ {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
+ {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
{0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
--
1.7.3.2


2010-12-12 13:34:42

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 2/7] ath9k_hw: fix the slot time setting for long distance links

Testing shows that adjusting the slot time based on the coverage class
produces very high latencies and very low throughput on long distance links.

Adjusting only the ACK timeout and leaving the slot time at the regular
values - while technically not optimal for CSMA - works a lot better on
long links (tested with 10 km distance)

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/hw.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 856a76e..3c8db81 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -808,7 +808,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ)
acktimeout += 64 - sifstime - ah->slottime;

- ath9k_hw_setslottime(ah, slottime);
+ ath9k_hw_setslottime(ah, ah->slottime);
ath9k_hw_set_ack_timeout(ah, acktimeout);
ath9k_hw_set_cts_timeout(ah, acktimeout);
if (ah->globaltxtimeout != (u32) -1)
--
1.7.3.2


2010-12-12 13:34:47

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 6/7] ath9k_hw: update AR9003 initvals for improved radar detection

Reduces the likelihood of false pulse detects in the hardware

Signed-off-by: Felix Fietkau <[email protected]>
---
.../net/wireless/ath/ath9k/ar9003_2p2_initvals.h | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index a14a5e4..ec50ca1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -638,6 +638,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
{0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0},
{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+ {0x0000a22c, 0x01026a2f, 0x01026a2f, 0x01026a2f, 0x01026a2f},
{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
{0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
{0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
@@ -680,7 +681,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x0000981c, 0x00020028},
{0x00009834, 0x6400a290},
{0x00009838, 0x0108ecff},
- {0x0000983c, 0x14750600},
+ {0x0000983c, 0x0d000600},
{0x00009880, 0x201fff00},
{0x00009884, 0x00001042},
{0x000098a4, 0x00200400},
@@ -722,7 +723,6 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
{0x0000a220, 0x00000000},
{0x0000a224, 0x00000000},
{0x0000a228, 0x10002310},
- {0x0000a22c, 0x01036a27},
{0x0000a23c, 0x00000000},
{0x0000a244, 0x0c000000},
{0x0000a2a0, 0x00000001},
--
1.7.3.2


Subject: Re: [PATCH 5/7] ath9k_hw: fix PA predistortion training power selection

On Sun, Dec 12, 2010 at 07:04:35PM +0530, Felix Fietkau wrote:
> The EEPROM contains scale factors for the tx power, which define
> the range of allowable difference between target power and training
> power. If the difference is too big, PA predistortion cannot be used.
> For 2.4 GHz there is only one scale factor, for 5 GHz there are
> three, depending on the specific frequency range.
>
> Signed-off-by: Felix Fietkau <[email protected]>
> ---
> drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 8 ++
> drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 99 ++++++++++++++++++++----
> drivers/net/wireless/ath/ath9k/ar9003_phy.h | 8 ++
> drivers/net/wireless/ath/ath9k/hw.h | 2 +
> drivers/net/wireless/ath/ath9k/main.c | 4 +-
> 5 files changed, 104 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
> index 5ad37d0..ff03b42 100644
> --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
> +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
> @@ -4798,6 +4798,14 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
> /* Write target power array to registers */
> ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
> ar9003_hw_calibration_apply(ah, chan->channel);
> +
> + if (IS_CHAN_2GHZ(chan))
> + i = ALL_TARGET_HT20_0_8_16;
> + else if (IS_CHAN_HT40(chan))
> + i = ALL_TARGET_HT40_7;

It looks like ALL_TARGET_HT40_0_8_16 being used in 11NGHT40.
> + else
> + i = ALL_TARGET_HT20_7;
> + ah->paprd_target_power = targetPowerValT2[i];
> }
>
> static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah,
> diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
> +static int get_streams(int mask)
> +{
> + return !!(mask & BIT(0)) + !!(mask & BIT(1)) + !!(mask & BIT(2));
> +}

ah->caps.max_txchains can be used instead of this function.

> +
> +static int ar9003_get_training_power_5g(struct ath_hw *ah)
> +{
> + struct ath_common *common = ath9k_hw_common(ah);
> + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
> + struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G;
> + struct ath9k_channel *chan = ah->curchan;
> + unsigned int power, scale, delta;
> +
> + if (chan->channel >= 5700)
> + scale = MS(hdr->papdRateMaskHt20, AR9300_PAPRD_SCALE_1);
> + else if (chan->channel >= 5400)
> + scale = MS(hdr->papdRateMaskHt40, AR9300_PAPRD_SCALE_2);
> + else
> + scale = MS(hdr->papdRateMaskHt40, AR9300_PAPRD_SCALE_1);

A helper function would be nice to get the paprd scale factor which
will also be used to disable paprd for particular rates. Anyway, i'm
doing changes to disable paprd based on scale factor and tx power,
i'll add a helper in my series.

Vasanth

2010-12-12 13:34:46

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 3/7] ath9k: fix PA predistortion thermal measurement handling

To be able to measure the thermal values correctly for PAPRD, we need
to send training frames before setting up the gain table for the measurement,
and then again afterwards for the actual training.

For further improvement, send training frames at MCS0 instead of 54 MBit/s
legacy. That way we can use the No-ACK flag for the transmission, which
speeds up PAPRD training in general, as the hardware won't have to
retransmit and wait for ACK timeout (was previously set to 4 * 6
transmission attempts).

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/main.c | 74 +++++++++++++++++++-------------
1 files changed, 44 insertions(+), 30 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index daa3c9f..bcadf9c 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -320,6 +320,42 @@ static void ath_paprd_activate(struct ath_softc *sc)
ath9k_ps_restore(sc);
}

+static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ath_tx_control txctl;
+ int time_left;
+
+ memset(&txctl, 0, sizeof(txctl));
+ txctl.txq = sc->tx.txq_map[WME_AC_BE];
+
+ memset(tx_info, 0, sizeof(*tx_info));
+ tx_info->band = hw->conf.channel->band;
+ tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ tx_info->control.rates[0].idx = 0;
+ tx_info->control.rates[0].count = 1;
+ tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
+ tx_info->control.rates[1].idx = -1;
+
+ init_completion(&sc->paprd_complete);
+ sc->paprd_pending = true;
+ txctl.paprd = BIT(chain);
+ if (ath_tx_start(hw, skb, &txctl) != 0)
+ return false;
+
+ time_left = wait_for_completion_timeout(&sc->paprd_complete,
+ msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
+ sc->paprd_pending = false;
+
+ if (!time_left)
+ ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CALIBRATE,
+ "Timeout waiting for paprd training on TX chain %d\n",
+ chain);
+
+ return !!time_left;
+}
+
void ath_paprd_calibrate(struct work_struct *work)
{
struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
@@ -327,18 +363,12 @@ void ath_paprd_calibrate(struct work_struct *work)
struct ath_hw *ah = sc->sc_ah;
struct ieee80211_hdr *hdr;
struct sk_buff *skb = NULL;
- struct ieee80211_tx_info *tx_info;
- int band = hw->conf.channel->band;
- struct ieee80211_supported_band *sband = &sc->sbands[band];
- struct ath_tx_control txctl;
struct ath9k_hw_cal_data *caldata = ah->caldata;
struct ath_common *common = ath9k_hw_common(ah);
int ftype;
int chain_ok = 0;
int chain;
int len = 1800;
- int time_left;
- int i;

if (!caldata)
return;
@@ -347,8 +377,6 @@ void ath_paprd_calibrate(struct work_struct *work)
if (!skb)
return;

- tx_info = IEEE80211_SKB_CB(skb);
-
skb_put(skb, len);
memset(skb->data, 0, len);
hdr = (struct ieee80211_hdr *)skb->data;
@@ -359,9 +387,6 @@ void ath_paprd_calibrate(struct work_struct *work)
memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);

- memset(&txctl, 0, sizeof(txctl));
- txctl.txq = sc->tx.txq_map[WME_AC_BE];
-
ath9k_ps_wakeup(sc);
ar9003_paprd_init_table(ah);
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
@@ -369,30 +394,19 @@ void ath_paprd_calibrate(struct work_struct *work)
continue;

chain_ok = 0;
- memset(tx_info, 0, sizeof(*tx_info));
- tx_info->band = band;

- for (i = 0; i < 4; i++) {
- tx_info->control.rates[i].idx = sband->n_bitrates - 1;
- tx_info->control.rates[i].count = 6;
- }
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Sending PAPRD frame for thermal measurement "
+ "on chain %d\n", chain);
+ if (!ath_paprd_send_frame(sc, skb, chain))
+ goto fail_paprd;

- init_completion(&sc->paprd_complete);
- sc->paprd_pending = true;
ar9003_paprd_setup_gain_table(ah, chain);
- txctl.paprd = BIT(chain);
- if (ath_tx_start(hw, skb, &txctl) != 0)
- break;

- time_left = wait_for_completion_timeout(&sc->paprd_complete,
- msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
- sc->paprd_pending = false;
- if (!time_left) {
- ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
- "Timeout waiting for paprd training on TX chain %d\n",
- chain);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Sending PAPRD training frame on chain %d\n", chain);
+ if (!ath_paprd_send_frame(sc, skb, chain))
goto fail_paprd;
- }

if (!ar9003_paprd_is_done(ah))
break;
--
1.7.3.2


Subject: Re: [PATCH 5/7] ath9k_hw: fix PA predistortion training power selection

On Mon, Dec 13, 2010 at 12:49:11PM +0530, Felix Fietkau wrote:
> On 2010-12-13 7:02 AM, Vasanthakumar Thiagarajan wrote:
> > On Sun, Dec 12, 2010 at 07:04:35PM +0530, Felix Fietkau wrote:
> >> The EEPROM contains scale factors for the tx power, which define
> >> the range of allowable difference between target power and training
> >> power. If the difference is too big, PA predistortion cannot be used.
> >> For 2.4 GHz there is only one scale factor, for 5 GHz there are
> >> three, depending on the specific frequency range.
> >>
> >> Signed-off-by: Felix Fietkau <[email protected]>
> >> ---
> >> drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 8 ++
> >> drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 99 ++++++++++++++++++++----
> >> drivers/net/wireless/ath/ath9k/ar9003_phy.h | 8 ++
> >> drivers/net/wireless/ath/ath9k/hw.h | 2 +
> >> drivers/net/wireless/ath/ath9k/main.c | 4 +-
> >> 5 files changed, 104 insertions(+), 17 deletions(-)

> >> +static int get_streams(int mask)
> >> +{
> >> + return !!(mask & BIT(0)) + !!(mask & BIT(1)) + !!(mask & BIT(2));
> >> +}
> > ah->caps.max_txchains can be used instead of this function.
> No, it cannot. I need the number of active chains, not the number of
> chains that the hardware is capable of using.

Ah, right.
>
> >> +
> >> +static int ar9003_get_training_power_5g(struct ath_hw *ah)
> >> +{
> >> + struct ath_common *common = ath9k_hw_common(ah);
> >> + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
> >> + struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G;
> >> + struct ath9k_channel *chan = ah->curchan;
> >> + unsigned int power, scale, delta;
> >> +
> >> + if (chan->channel >= 5700)
> >> + scale = MS(hdr->papdRateMaskHt20, AR9300_PAPRD_SCALE_1);
> >> + else if (chan->channel >= 5400)
> >> + scale = MS(hdr->papdRateMaskHt40, AR9300_PAPRD_SCALE_2);
> >> + else
> >> + scale = MS(hdr->papdRateMaskHt40, AR9300_PAPRD_SCALE_1);
> >
> > A helper function would be nice to get the paprd scale factor which
> > will also be used to disable paprd for particular rates. Anyway, i'm
> > doing changes to disable paprd based on scale factor and tx power,
> > i'll add a helper in my series.
> OK.

seems like it is missing endian conversion for big endian platform ?.

Vasanth

2010-12-12 13:34:46

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 4/7] ath9k_hw: fix the PA predistortion rate mask

The EEPROM PAPRD rate mask fields only contain mask values for actual
rates in the low 25 bits. The upper bits are reserved for tx power
scale values. Add the proper mask definitions and use them before
writing the values to the register.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h | 6 ++++++
drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 4 ++--
2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
index 620821e..efb6a02 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
@@ -31,6 +31,12 @@
#define AR9300_ANT_16S 25
#define AR9300_FUTURE_MODAL_SZ 6

+#define AR9300_PAPRD_RATE_MASK 0x01ffffff
+#define AR9300_PAPRD_SCALE_1 0x0e000000
+#define AR9300_PAPRD_SCALE_1_S 25
+#define AR9300_PAPRD_SCALE_2 0x70000000
+#define AR9300_PAPRD_SCALE_2_S 28
+
/* Delta from which to start power to pdadc table */
/* This offset is used in both open loop and closed loop power control
* schemes. In open loop power control, it is not really needed, but for
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
index 74cff43..cdca4c3 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
@@ -52,8 +52,8 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
else
hdr = &eep->modalHeader2G;

- am_mask = le32_to_cpu(hdr->papdRateMaskHt20);
- ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40);
+ am_mask = le32_to_cpu(hdr->papdRateMaskHt20) & AR9300_PAPRD_RATE_MASK;
+ ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40) & AR9300_PAPRD_RATE_MASK;

REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask);
--
1.7.3.2


2010-12-13 07:19:16

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH 5/7] ath9k_hw: fix PA predistortion training power selection

On 2010-12-13 7:02 AM, Vasanthakumar Thiagarajan wrote:
> On Sun, Dec 12, 2010 at 07:04:35PM +0530, Felix Fietkau wrote:
>> The EEPROM contains scale factors for the tx power, which define
>> the range of allowable difference between target power and training
>> power. If the difference is too big, PA predistortion cannot be used.
>> For 2.4 GHz there is only one scale factor, for 5 GHz there are
>> three, depending on the specific frequency range.
>>
>> Signed-off-by: Felix Fietkau <[email protected]>
>> ---
>> drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 8 ++
>> drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 99 ++++++++++++++++++++----
>> drivers/net/wireless/ath/ath9k/ar9003_phy.h | 8 ++
>> drivers/net/wireless/ath/ath9k/hw.h | 2 +
>> drivers/net/wireless/ath/ath9k/main.c | 4 +-
>> 5 files changed, 104 insertions(+), 17 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
>> index 5ad37d0..ff03b42 100644
>> --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
>> +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
>> @@ -4798,6 +4798,14 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
>> /* Write target power array to registers */
>> ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
>> ar9003_hw_calibration_apply(ah, chan->channel);
>> +
>> + if (IS_CHAN_2GHZ(chan))
>> + i = ALL_TARGET_HT20_0_8_16;
>> + else if (IS_CHAN_HT40(chan))
>> + i = ALL_TARGET_HT40_7;
>
> It looks like ALL_TARGET_HT40_0_8_16 being used in 11NGHT40.
You're right, I'll resend.

>> + else
>> + i = ALL_TARGET_HT20_7;
>> + ah->paprd_target_power = targetPowerValT2[i];
>> }
>>
>> static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah,
>> diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
>> +static int get_streams(int mask)
>> +{
>> + return !!(mask & BIT(0)) + !!(mask & BIT(1)) + !!(mask & BIT(2));
>> +}
> ah->caps.max_txchains can be used instead of this function.
No, it cannot. I need the number of active chains, not the number of
chains that the hardware is capable of using.

>> +
>> +static int ar9003_get_training_power_5g(struct ath_hw *ah)
>> +{
>> + struct ath_common *common = ath9k_hw_common(ah);
>> + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
>> + struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G;
>> + struct ath9k_channel *chan = ah->curchan;
>> + unsigned int power, scale, delta;
>> +
>> + if (chan->channel >= 5700)
>> + scale = MS(hdr->papdRateMaskHt20, AR9300_PAPRD_SCALE_1);
>> + else if (chan->channel >= 5400)
>> + scale = MS(hdr->papdRateMaskHt40, AR9300_PAPRD_SCALE_2);
>> + else
>> + scale = MS(hdr->papdRateMaskHt40, AR9300_PAPRD_SCALE_1);
>
> A helper function would be nice to get the paprd scale factor which
> will also be used to disable paprd for particular rates. Anyway, i'm
> doing changes to disable paprd based on scale factor and tx power,
> i'll add a helper in my series.
OK.

- Felix

2010-12-12 13:34:42

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 5/7] ath9k_hw: fix PA predistortion training power selection

The EEPROM contains scale factors for the tx power, which define
the range of allowable difference between target power and training
power. If the difference is too big, PA predistortion cannot be used.
For 2.4 GHz there is only one scale factor, for 5 GHz there are
three, depending on the specific frequency range.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 8 ++
drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 99 ++++++++++++++++++++----
drivers/net/wireless/ath/ath9k/ar9003_phy.h | 8 ++
drivers/net/wireless/ath/ath9k/hw.h | 2 +
drivers/net/wireless/ath/ath9k/main.c | 4 +-
5 files changed, 104 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 5ad37d0..ff03b42 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -4798,6 +4798,14 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
/* Write target power array to registers */
ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
ar9003_hw_calibration_apply(ah, chan->channel);
+
+ if (IS_CHAN_2GHZ(chan))
+ i = ALL_TARGET_HT20_0_8_16;
+ else if (IS_CHAN_HT40(chan))
+ i = ALL_TARGET_HT40_7;
+ else
+ i = ALL_TARGET_HT20_7;
+ ah->paprd_target_power = targetPowerValT2[i];
}

static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
index cdca4c3..dd6057b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
@@ -30,9 +30,66 @@ void ar9003_paprd_enable(struct ath_hw *ah, bool val)
}
EXPORT_SYMBOL(ar9003_paprd_enable);

-static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
+static int ar9003_get_training_power_2g(struct ath_hw *ah)
{
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+ struct ar9300_modal_eep_header *hdr = &eep->modalHeader2G;
+ unsigned int power, scale, delta;
+
+ scale = MS(hdr->papdRateMaskHt20, AR9300_PAPRD_SCALE_1);
+ power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
+ AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
+
+ delta = abs((int) ah->paprd_target_power - (int) power);
+ if (delta > scale)
+ return -1;
+
+ if (delta < 4)
+ power -= 4 - delta;
+
+ return power;
+}
+
+static int get_streams(int mask)
+{
+ return !!(mask & BIT(0)) + !!(mask & BIT(1)) + !!(mask & BIT(2));
+}
+
+static int ar9003_get_training_power_5g(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+ struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G;
+ struct ath9k_channel *chan = ah->curchan;
+ unsigned int power, scale, delta;
+
+ if (chan->channel >= 5700)
+ scale = MS(hdr->papdRateMaskHt20, AR9300_PAPRD_SCALE_1);
+ else if (chan->channel >= 5400)
+ scale = MS(hdr->papdRateMaskHt40, AR9300_PAPRD_SCALE_2);
+ else
+ scale = MS(hdr->papdRateMaskHt40, AR9300_PAPRD_SCALE_1);
+
+ if (IS_CHAN_HT40(chan))
+ power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8,
+ AR_PHY_POWERTX_RATE8_POWERTXHT40_5);
+ else
+ power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6,
+ AR_PHY_POWERTX_RATE6_POWERTXHT20_5);
+
+ power += scale;
+ delta = abs((int) ah->paprd_target_power - (int) power);
+ if (delta > scale)
+ return -1;
+
+ power += 2 * get_streams(common->tx_chainmask);
+ return power;
+}
+
+static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
struct ar9300_modal_eep_header *hdr;
static const u32 ctrl0[3] = {
AR_PHY_PAPRD_CTRL0_B0,
@@ -45,6 +102,7 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
AR_PHY_PAPRD_CTRL1_B2
};
u32 am_mask, ht40_mask;
+ int training_power;
int i;

if (ah->curchan && IS_CHAN_5GHZ(ah->curchan))
@@ -55,11 +113,25 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
am_mask = le32_to_cpu(hdr->papdRateMaskHt20) & AR9300_PAPRD_RATE_MASK;
ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40) & AR9300_PAPRD_RATE_MASK;

+ if (IS_CHAN_2GHZ(ah->curchan))
+ training_power = ar9003_get_training_power_2g(ah);
+ else
+ training_power = ar9003_get_training_power_5g(ah);
+
+ if (training_power < 0) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "PAPRD target power delta out of range");
+ return -ERANGE;
+ }
+ ah->paprd_training_power = training_power;
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Training power: %d, Target power: %d\n",
+ ah->paprd_training_power, ah->paprd_target_power);
+
REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask);

-
for (i = 0; i < ah->caps.max_txchains; i++) {
REG_RMW_FIELD(ah, ctrl0[i],
AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1);
@@ -141,6 +213,7 @@ static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
AR_PHY_PAPRD_PRE_POST_SCALING, 185706);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,
AR_PHY_PAPRD_PRE_POST_SCALING, 175487);
+ return 0;
}

static void ar9003_paprd_get_gain_table(struct ath_hw *ah)
@@ -595,15 +668,10 @@ void ar9003_paprd_populate_single_table(struct ath_hw *ah,
{
u32 *paprd_table_val = caldata->pa_table[chain];
u32 small_signal_gain = caldata->small_signal_gain[chain];
- u32 training_power;
+ u32 training_power = ah->paprd_training_power;
u32 reg = 0;
int i;

- training_power =
- REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
- AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
- training_power -= 4;
-
if (chain == 0)
reg = AR_PHY_PAPRD_MEM_TAB_B0;
else if (chain == 1)
@@ -643,14 +711,8 @@ EXPORT_SYMBOL(ar9003_paprd_populate_single_table);

int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
{
-
unsigned int i, desired_gain, gain_index;
- unsigned int train_power;
-
- train_power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
- AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
-
- train_power = train_power - 4;
+ unsigned int train_power = ah->paprd_training_power;

desired_gain = ar9003_get_desired_gain(ah, chain, train_power);

@@ -716,7 +778,12 @@ EXPORT_SYMBOL(ar9003_paprd_create_curve);

int ar9003_paprd_init_table(struct ath_hw *ah)
{
- ar9003_paprd_setup_single_table(ah);
+ int ret;
+
+ ret = ar9003_paprd_setup_single_table(ah);
+ if (ret < 0)
+ return ret;
+
ar9003_paprd_get_gain_table(ah);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 6f811c7..59bab6b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -1090,6 +1090,14 @@
#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0 0x3F
#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0_S 0

+#define AR_PHY_POWERTX_RATE6 (AR_SM_BASE + 0x1d4)
+#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5 0x3F00
+#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5_S 8
+
+#define AR_PHY_POWERTX_RATE8 (AR_SM_BASE + 0x1dc)
+#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5 0x3F00
+#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5_S 8
+
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);

#endif /* AR9003_PHY_H */
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index c20e047..97f22c4 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -833,6 +833,8 @@ struct ath_hw {
u32 bb_watchdog_last_status;
u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */

+ unsigned int paprd_target_power;
+ unsigned int paprd_training_power;
u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES];
u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES];
/*
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index bcadf9c..378485b 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -373,6 +373,9 @@ void ath_paprd_calibrate(struct work_struct *work)
if (!caldata)
return;

+ if (ar9003_paprd_init_table(ah) < 0)
+ return;
+
skb = alloc_skb(len, GFP_KERNEL);
if (!skb)
return;
@@ -388,7 +391,6 @@ void ath_paprd_calibrate(struct work_struct *work)
memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);

ath9k_ps_wakeup(sc);
- ar9003_paprd_init_table(ah);
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
if (!(common->tx_chainmask & BIT(chain)))
continue;
--
1.7.3.2