Commit e702ba18 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville

ath9k_hw: fix endian issues with CTLs on AR9003

Parsing data using bitfields is messy, because it makes endian handling
much harder. AR9002 and earlier got it right, AR9003 got it wrong.
This might lead to either using too high or too low tx power values,
depending on frequency and eeprom settings.
Fix it by getting rid of the CTL related bitfields entirely and use
masks instead.
Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Cc: stable@kernel.org
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 9306990a
...@@ -55,6 +55,8 @@ ...@@ -55,6 +55,8 @@
#define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */ #define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */
#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ #define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */
#define CTL(_tpower, _flag) ((_tpower) | ((_flag) << 6))
static const struct ar9300_eeprom ar9300_default = { static const struct ar9300_eeprom ar9300_default = {
.eepromVersion = 2, .eepromVersion = 2,
.templateVersion = 2, .templateVersion = 2,
...@@ -290,20 +292,21 @@ static const struct ar9300_eeprom ar9300_default = { ...@@ -290,20 +292,21 @@ static const struct ar9300_eeprom ar9300_default = {
} }
}, },
.ctlPowerData_2G = { .ctlPowerData_2G = {
{ { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { {60, 1}, {60, 0}, {60, 0}, {60, 1} } }, { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
{ { {60, 1}, {60, 0}, {0, 0}, {0, 0} } }, { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
{ { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { {60, 0}, {60, 1}, {60, 1}, {60, 0} } }, { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
{ { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
{ { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
{ { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
}, },
.modalHeader5G = { .modalHeader5G = {
/* 4 idle,t1,t2,b (4 bits per setting) */ /* 4 idle,t1,t2,b (4 bits per setting) */
...@@ -568,56 +571,56 @@ static const struct ar9300_eeprom ar9300_default = { ...@@ -568,56 +571,56 @@ static const struct ar9300_eeprom ar9300_default = {
.ctlPowerData_5G = { .ctlPowerData_5G = {
{ {
{ {
{60, 1}, {60, 1}, {60, 1}, {60, 1}, CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
{60, 1}, {60, 1}, {60, 1}, {60, 0}, CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
} }
}, },
{ {
{ {
{60, 1}, {60, 1}, {60, 1}, {60, 1}, CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
{60, 1}, {60, 1}, {60, 1}, {60, 0}, CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
} }
}, },
{ {
{ {
{60, 0}, {60, 1}, {60, 0}, {60, 1}, CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
{60, 1}, {60, 1}, {60, 1}, {60, 1}, CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
} }
}, },
{ {
{ {
{60, 0}, {60, 1}, {60, 1}, {60, 0}, CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
{60, 1}, {60, 0}, {60, 0}, {60, 0}, CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
} }
}, },
{ {
{ {
{60, 1}, {60, 1}, {60, 1}, {60, 0}, CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
{60, 0}, {60, 0}, {60, 0}, {60, 0}, CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
} }
}, },
{ {
{ {
{60, 1}, {60, 1}, {60, 1}, {60, 1}, CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
{60, 1}, {60, 0}, {60, 0}, {60, 0}, CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
} }
}, },
{ {
{ {
{60, 1}, {60, 1}, {60, 1}, {60, 1}, CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
{60, 1}, {60, 1}, {60, 1}, {60, 1}, CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
} }
}, },
{ {
{ {
{60, 1}, {60, 1}, {60, 0}, {60, 1}, CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
{60, 1}, {60, 1}, {60, 1}, {60, 0}, CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
} }
}, },
{ {
{ {
{60, 1}, {60, 0}, {60, 1}, {60, 1}, CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
{60, 1}, {60, 1}, {60, 0}, {60, 1}, CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
} }
}, },
} }
...@@ -1827,9 +1830,9 @@ static u16 ar9003_hw_get_direct_edge_power(struct ar9300_eeprom *eep, ...@@ -1827,9 +1830,9 @@ static u16 ar9003_hw_get_direct_edge_power(struct ar9300_eeprom *eep,
struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G; struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G;
if (is2GHz) if (is2GHz)
return ctl_2g[idx].ctlEdges[edge].tPower; return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge]);
else else
return ctl_5g[idx].ctlEdges[edge].tPower; return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge]);
} }
static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep, static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep,
...@@ -1847,12 +1850,12 @@ static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep, ...@@ -1847,12 +1850,12 @@ static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep,
if (is2GHz) { if (is2GHz) {
if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 1) < freq && if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 1) < freq &&
ctl_2g[idx].ctlEdges[edge - 1].flag) CTL_EDGE_FLAGS(ctl_2g[idx].ctlEdges[edge - 1]))
return ctl_2g[idx].ctlEdges[edge - 1].tPower; return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge - 1]);
} else { } else {
if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 0) < freq && if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 0) < freq &&
ctl_5g[idx].ctlEdges[edge - 1].flag) CTL_EDGE_FLAGS(ctl_5g[idx].ctlEdges[edge - 1]))
return ctl_5g[idx].ctlEdges[edge - 1].tPower; return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge - 1]);
} }
return AR9300_MAX_RATE_POWER; return AR9300_MAX_RATE_POWER;
......
...@@ -261,17 +261,12 @@ struct cal_tgt_pow_ht { ...@@ -261,17 +261,12 @@ struct cal_tgt_pow_ht {
u8 tPow2x[14]; u8 tPow2x[14];
} __packed; } __packed;
struct cal_ctl_edge_pwr {
u8 tPower:6,
flag:2;
} __packed;
struct cal_ctl_data_2g { struct cal_ctl_data_2g {
struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_2G]; u8 ctlEdges[AR9300_NUM_BAND_EDGES_2G];
} __packed; } __packed;
struct cal_ctl_data_5g { struct cal_ctl_data_5g {
struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_5G]; u8 ctlEdges[AR9300_NUM_BAND_EDGES_5G];
} __packed; } __packed;
struct ar9300_eeprom { struct ar9300_eeprom {
......
...@@ -240,16 +240,16 @@ u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, ...@@ -240,16 +240,16 @@ u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
for (i = 0; (i < num_band_edges) && for (i = 0; (i < num_band_edges) &&
(pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
twiceMaxEdgePower = pRdEdgesPower[i].tPower; twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
break; break;
} else if ((i > 0) && } else if ((i > 0) &&
(freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
is2GHz))) { is2GHz))) {
if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
is2GHz) < freq && is2GHz) < freq &&
pRdEdgesPower[i - 1].flag) { CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
twiceMaxEdgePower = twiceMaxEdgePower =
pRdEdgesPower[i - 1].tPower; CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
} }
break; break;
} }
......
...@@ -233,6 +233,9 @@ ...@@ -233,6 +233,9 @@
#define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1) #define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1)
#define CTL_EDGE_TPOWER(_ctl) ((_ctl) & 0x3f)
#define CTL_EDGE_FLAGS(_ctl) (((_ctl) >> 6) & 0x03)
enum eeprom_param { enum eeprom_param {
EEP_NFTHRESH_5, EEP_NFTHRESH_5,
EEP_NFTHRESH_2, EEP_NFTHRESH_2,
...@@ -535,18 +538,10 @@ struct cal_target_power_ht { ...@@ -535,18 +538,10 @@ struct cal_target_power_ht {
u8 tPow2x[8]; u8 tPow2x[8];
} __packed; } __packed;
#ifdef __BIG_ENDIAN_BITFIELD
struct cal_ctl_edges {
u8 bChannel;
u8 flag:2, tPower:6;
} __packed;
#else
struct cal_ctl_edges { struct cal_ctl_edges {
u8 bChannel; u8 bChannel;
u8 tPower:6, flag:2; u8 ctl;
} __packed; } __packed;
#endif
struct cal_data_op_loop_ar9287 { struct cal_data_op_loop_ar9287 {
u8 pwrPdg[2][5]; u8 pwrPdg[2][5];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment