linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] ath5k: fix I/Q calibration (for real)
@ 2010-03-05  6:32 Bruno Randolf
  2010-03-05  6:33 ` [PATCH 2/3] ath5k: read eeprom IQ calibration values correctly for G mode Bruno Randolf
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Bruno Randolf @ 2010-03-05  6:32 UTC (permalink / raw)
  To: linville; +Cc: 8an, ath5k-devel, linux-wireless, mickflemm

I/Q calibration was completely broken, resulting in a high number of CRC errors
on received packets. before i could see around 10% to 20% CRC errors, with this
patch they are between 0% and 3%.

1.) the removal of the mask in commit "ath5k: Fix I/Q calibration
(f1cf2dbd0f798b71b1590e7aca6647f2caef1649)" resulted in no mask beeing used
when writing the I/Q values into the register. additional errors in the
calculation of the values (see 2.) resulted too high numbers, exceeding the
masks, so wrong values like 0xfffffffe were written. to be safe we should
always use the bitmask when writing parts of a register.

2.) using a (s32) cast for q_coff is a wrong conversion to signed, since we
convert to a signed value later by substracting 128. this resulted in too low
numbers for Q many times, which were limited to -16 by the boundary check later
on.

3.) checked everything against the HAL sources and took over comments and minor
optimizations from there.

4.) we can't use ENABLE_BITS when we want to write a number (the number can
contain zeros). also always write the correction values first and set ENABLE
bit last, like the HAL does.

Signed-off-by: Bruno Randolf <br1@einfach.org>
---
 drivers/net/wireless/ath/ath5k/phy.c |   35 +++++++++++++++++++++-------------
 drivers/net/wireless/ath/ath5k/reg.h |    1 +
 2 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 3fa4f4d..4977d22 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1386,38 +1386,47 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
 		goto done;
 
 	/* Calibration has finished, get the results and re-run */
+
+	/* workaround against empty results which can apparently happen on 5212 */
 	for (i = 0; i <= 10; i++) {
 		iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
 		i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
 		q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
+		ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+			"iq_corr:%x i_pwr:%x q_pwr:%x", iq_corr, i_pwr, q_pwr);
+		if (i_pwr && q_pwr)
+			break;
 	}
 
 	i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
 	q_coffd = q_pwr >> 7;
 
-	/* No correction */
-	if (i_coffd == 0 || q_coffd == 0)
+	/* protect against divide by 0 and loss of sign bits */
+	if (i_coffd == 0 || q_coffd < 2)
 		goto done;
 
-	i_coff = ((-iq_corr) / i_coffd);
-
-	/* Boundary check */
+	i_coff = (-iq_corr) / i_coffd;
+	/* Boundary check (signed 6 bit) */
 	if (i_coff > 31)
 		i_coff = 31;
-	if (i_coff < -32)
+	else if (i_coff < -32)
 		i_coff = -32;
 
-	q_coff = (((s32)i_pwr / q_coffd) - 128);
-
-	/* Boundary check */
+	q_coff = (i_pwr / q_coffd) - 128;
+	/* Boundary check (signed 5 bit) */
 	if (q_coff > 15)
 		q_coff = 15;
-	if (q_coff < -16)
+	else if (q_coff < -16)
 		q_coff = -16;
 
-	/* Commit new I/Q value */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
-		((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
+	ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+			"new I:%d Q:%d (i_coffd:%x q_coffd:%x)",
+			i_coff, q_coff, i_coffd, q_coffd);
+
+	/* Commit new I/Q values (set enable bit last to match HAL sources) */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF, i_coff);
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF, q_coff);
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE);
 
 	/* Re-enable calibration -if we don't we'll commit
 	 * the same values again and again */
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index 4cb9c5d..1464f89 100644
--- a/drivers/net/wireless/ath/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
@@ -2187,6 +2187,7 @@
  */
 #define	AR5K_PHY_IQ			0x9920			/* Register Address */
 #define	AR5K_PHY_IQ_CORR_Q_Q_COFF	0x0000001f	/* Mask for q correction info */
+#define	AR5K_PHY_IQ_CORR_Q_Q_COFF_S	0
 #define	AR5K_PHY_IQ_CORR_Q_I_COFF	0x000007e0	/* Mask for i correction info */
 #define	AR5K_PHY_IQ_CORR_Q_I_COFF_S	5
 #define	AR5K_PHY_IQ_CORR_ENABLE		0x00000800	/* Enable i/q correction */


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

* [PATCH 2/3] ath5k: read eeprom IQ calibration values correctly for G mode
  2010-03-05  6:32 [PATCH 1/3] ath5k: fix I/Q calibration (for real) Bruno Randolf
@ 2010-03-05  6:33 ` Bruno Randolf
  2010-03-05  6:33 ` [PATCH 3/3] ath5k: IQ calibration for AR5211 is slightly different Bruno Randolf
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Bruno Randolf @ 2010-03-05  6:33 UTC (permalink / raw)
  To: linville; +Cc: 8an, ath5k-devel, linux-wireless, mickflemm

we read the IQ correction values (i_cal and q_cal) for G mode from a wrong
location (the same shifts as for A mode is applied which is incorrect). use
correct locations, matching the docs and HAL sources.

also we should write IQ correction only when we have that information in the
EEPROM, starting from version 4. also write it in the same way as we do in the
periodic recalibration (enable last), just to be sure.

Signed-off-by: Bruno Randolf <br1@einfach.org>
---
 drivers/net/wireless/ath/ath5k/eeprom.c |    4 ++--
 drivers/net/wireless/ath/ath5k/reset.c  |   15 +++++++++------
 2 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index 6a3f4da..10b5226 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -429,8 +429,8 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
 			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
 
 		AR5K_EEPROM_READ(o++, val);
-		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
-		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+		ee->ee_i_cal[mode] = (val >> 5) & 0x3f;
+		ee->ee_q_cal[mode] = val & 0x1f;
 
 		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
 			AR5K_EEPROM_READ(o++, val);
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 6d9a1e8..e9e69dc 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -851,12 +851,15 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
 				AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
 				AR5K_INIT_CYCRSSI_THR1);
 
-	/* I/Q correction
-	 * TODO: Per channel i/q infos ? */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
-		AR5K_PHY_IQ_CORR_ENABLE |
-		(ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
-		ee->ee_q_cal[ee_mode]);
+	/* I/Q correction (set enable bit last to match HAL sources) */
+	/* TODO: Per channel i/q infos ? */
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF,
+			    ee->ee_i_cal[ee_mode]);
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF,
+			    ee->ee_q_cal[ee_mode]);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE);
+	}
 
 	/* Heavy clipping -disable for now */
 	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1)


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

* [PATCH 3/3] ath5k: IQ calibration for AR5211 is slightly different
  2010-03-05  6:32 [PATCH 1/3] ath5k: fix I/Q calibration (for real) Bruno Randolf
  2010-03-05  6:33 ` [PATCH 2/3] ath5k: read eeprom IQ calibration values correctly for G mode Bruno Randolf
@ 2010-03-05  6:33 ` Bruno Randolf
  2010-03-05 13:26 ` [PATCH 1/3] ath5k: fix I/Q calibration (for real) Bob Copeland
  2010-03-05 13:33 ` Bob Copeland
  3 siblings, 0 replies; 5+ messages in thread
From: Bruno Randolf @ 2010-03-05  6:33 UTC (permalink / raw)
  To: linville; +Cc: 8an, ath5k-devel, linux-wireless, mickflemm

according to the HAL sources the calculation of the Q value is slightly
different for AR5211 chips.

i couldn't test this since IQ calibration never finishes on older parts. this
is a different problem...

Signed-off-by: Bruno Randolf <br1@einfach.org>
---
 drivers/net/wireless/ath/ath5k/phy.c |   11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 4977d22..b474d51 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1399,7 +1399,11 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
 	}
 
 	i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
-	q_coffd = q_pwr >> 7;
+
+	if (ah->ah_version == AR5K_AR5211)
+		q_coffd = q_pwr >> 6;
+	else
+		q_coffd = q_pwr >> 7;
 
 	/* protect against divide by 0 and loss of sign bits */
 	if (i_coffd == 0 || q_coffd < 2)
@@ -1412,7 +1416,10 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
 	else if (i_coff < -32)
 		i_coff = -32;
 
-	q_coff = (i_pwr / q_coffd) - 128;
+	if (ah->ah_version == AR5K_AR5211)
+		q_coff = (i_pwr / q_coffd) - 64;
+	else
+		q_coff = (i_pwr / q_coffd) - 128;
 	/* Boundary check (signed 5 bit) */
 	if (q_coff > 15)
 		q_coff = 15;


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

* Re: [PATCH 1/3] ath5k: fix I/Q calibration (for real)
  2010-03-05  6:32 [PATCH 1/3] ath5k: fix I/Q calibration (for real) Bruno Randolf
  2010-03-05  6:33 ` [PATCH 2/3] ath5k: read eeprom IQ calibration values correctly for G mode Bruno Randolf
  2010-03-05  6:33 ` [PATCH 3/3] ath5k: IQ calibration for AR5211 is slightly different Bruno Randolf
@ 2010-03-05 13:26 ` Bob Copeland
  2010-03-05 13:33 ` Bob Copeland
  3 siblings, 0 replies; 5+ messages in thread
From: Bob Copeland @ 2010-03-05 13:26 UTC (permalink / raw)
  To: Bruno Randolf; +Cc: linville, 8an, ath5k-devel, linux-wireless, mickflemm

On Fri, Mar 5, 2010 at 1:32 AM, Bruno Randolf <br1@einfach.org> wrote:
> I/Q calibration was completely broken, resulting in a high number of CRC errors
> on received packets. before i could see around 10% to 20% CRC errors, with this
> patch they are between 0% and 3%.

Er, ouch.  This is definitely stable material -- can
you add cc to stable@kernel.org?

> -       i_coff = ((-iq_corr) / i_coffd);
> -
> -       /* Boundary check */
> +       i_coff = (-iq_corr) / i_coffd;
> +       /* Boundary check (signed 6 bit) */


>        if (i_coff > 31)
>                i_coff = 31;
> -       if (i_coff < -32)
> +       else if (i_coff < -32)
>                i_coff = -32;

Can't we just do

i_coff &= 0x3f;


Boundary check */
> +       q_coff = (i_pwr / q_coffd) - 128;
> +       /* Boundary check (signed 5 bit) */
>        if (q_coff > 15)
>                q_coff = 15;

q_coff &= 0x1f;

... and then these are equivalent to the masks we
already use in WRITE_BITS, right?

-- 
Bob Copeland %% www.bobcopeland.com

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

* Re: [PATCH 1/3] ath5k: fix I/Q calibration (for real)
  2010-03-05  6:32 [PATCH 1/3] ath5k: fix I/Q calibration (for real) Bruno Randolf
                   ` (2 preceding siblings ...)
  2010-03-05 13:26 ` [PATCH 1/3] ath5k: fix I/Q calibration (for real) Bob Copeland
@ 2010-03-05 13:33 ` Bob Copeland
  3 siblings, 0 replies; 5+ messages in thread
From: Bob Copeland @ 2010-03-05 13:33 UTC (permalink / raw)
  To: Bruno Randolf; +Cc: linville, 8an, ath5k-devel, linux-wireless, mickflemm

On Fri, Mar 05, 2010 at 03:32:55PM +0900, Bruno Randolf wrote:

Um, disregard my mask thing, that was the original bug
(-128 when masked to 6 bits overflows).  Still, we can use:

   i_coff = clamp(i_coff, -32, 31);

-- 
Bob Copeland %% www.bobcopeland.com


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

end of thread, other threads:[~2010-03-05 13:34 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-05  6:32 [PATCH 1/3] ath5k: fix I/Q calibration (for real) Bruno Randolf
2010-03-05  6:33 ` [PATCH 2/3] ath5k: read eeprom IQ calibration values correctly for G mode Bruno Randolf
2010-03-05  6:33 ` [PATCH 3/3] ath5k: IQ calibration for AR5211 is slightly different Bruno Randolf
2010-03-05 13:26 ` [PATCH 1/3] ath5k: fix I/Q calibration (for real) Bob Copeland
2010-03-05 13:33 ` Bob Copeland

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).