diff mbox

ar9170: implement frequency calibration for one-stage/openfw

Message ID 200909032025.31260.chunkeey@googlemail.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Christian Lamparter Sept. 3, 2009, 6:25 p.m. UTC
This patch ports some code from the vendor driver, which is
supposed to upload the right calibration values for the
chosen frequency.

In theory, this should give a better range and throughput
for all users with the open, or one-stage firmware.

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
---
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Andrew Morton Sept. 19, 2009, 12:02 a.m. UTC | #1
On Thu, 3 Sep 2009 20:25:31 +0200
Christian Lamparter <chunkeey@googlemail.com> wrote:

> This patch ports some code from the vendor driver, which is
> supposed to upload the right calibration values for the
> chosen frequency.
> 
> In theory, this should give a better range and throughput
> for all users with the open, or one-stage firmware.
> 
> ...
>
> +		for (i = 0; i < 76; i++) {
> +			u32 phy_data;
> +			u8 tmp;
> +
> +			if (i < 25) {
> +				tmp = ar9170_interpolate_val(i, &pwrs[0][0],
> +							     &vpds[0][0]);
> +			} else {
> +				tmp = ar9170_interpolate_val(i - 12,
> +							     &pwrs[1][0],
> +							     &vpds[1][0]);
> +			}
> +
> +			phy_data |= tmp << ((i & 3) << 3);

Clearly buggy and the compiler warns.  The value of phy_data is unknown
here.

How did this get all the way into mainline?

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joerg Albert Sept. 19, 2009, 12:21 p.m. UTC | #2
On 09/19/2009 02:02 AM, Andrew Morton wrote:
> On Thu, 3 Sep 2009 20:25:31 +0200
> Christian Lamparter <chunkeey@googlemail.com> wrote:
> 
>> This patch ports some code from the vendor driver, which is
>> supposed to upload the right calibration values for the
>> chosen frequency.
>>
>> In theory, this should give a better range and throughput
>> for all users with the open, or one-stage firmware.
>>
>> ...
>>
>> +		for (i = 0; i < 76; i++) {
>> +			u32 phy_data;
>> +			u8 tmp;
>> +
>> +			if (i < 25) {
>> +				tmp = ar9170_interpolate_val(i, &pwrs[0][0],
>> +							     &vpds[0][0]);
>> +			} else {
>> +				tmp = ar9170_interpolate_val(i - 12,
>> +							     &pwrs[1][0],
>> +							     &vpds[1][0]);
>> +			}
>> +
>> +			phy_data |= tmp << ((i & 3) << 3);
> 
> Clearly buggy and the compiler warns.  The value of phy_data is unknown
> here.
> 
> How did this get all the way into mainline?

Strangely it compiles without any warning for me with the latest linux-wireless:

 joerg@nc10:~/src/wireless.gits/wireless-testing$ gcc --version
gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3
joerg@nc10:~/src/wireless.gits/wireless-testing$ git describe
v2.6.31-38258-g389ce02
joerg@nc10:~/src/wireless.gits/wireless-testing/drivers/net/wireless/ath/ar9170$ grep phy_data phy.c
                        u32 phy_data;
                        phy_data |= tmp << ((i & 3) << 3);
                                                (i & ~3), phy_data);
                                phy_data = 0;

joerg@nc10:~/src/wireless.gits/wireless-testing$ make modules
...
  CC [M]  drivers/net/wireless/ath/ar9170/mac.o
  CC [M]  drivers/net/wireless/ath/ar9170/phy.o
  CC [M]  drivers/net/wireless/ath/ar9170/led.o

make V=1 says:

  gcc -Wp,-MD,drivers/net/wireless/ath/ar9170/.phy.o.d  -nostdinc -isystem 
/usr/lib/gcc/i486-linux-gnu/4.3.3/include -Iinclude  
-I/home/joerg/src/wireless.gits/wireless-testing/arch/x86/include -include 
include/linux/autoconf.h -D__KERNEL__ -Wall -Wundef -Wstrict-prototypes 
-Wno-trigraphs -fno-strict-aliasing -fno-common 
-Werror-implicit-function-declaration -Wno-format-security 
-fno-delete-null-pointer-checks -O2 -m32 -msoft-float -mregparm=3 
-freg-struct-return -mpreferred-stack-boundary=2 -march=i686 -mtune=pentium3 
-mtune=generic -Wa,-mtune=generic32 -ffreestanding -pipe -Wno-sign-compare 
-fno-asynchronous-unwind-tables -mno-sse -mno-mmx -mno-sse2 -mno-3dnow 
-fno-stack-protector -fno-omit-frame-pointer -fno-optimize-sibling-calls -g 
-Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow  -DMODULE 
-D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(phy)"  
-D"KBUILD_MODNAME=KBUILD_STR(ar9170usb)"  -c -o 
drivers/net/wireless/ath/ar9170/.tmp_phy.o drivers/net/wireless/ath/ar9170/phy.c


Adding "-Wuninitialized" didn't help, acc. to the doc it is switched on
with -Wall for -O2.
Is this a regression of gcc?

Regards,
Jörg.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c
index df86f70..be96f50 100644
--- a/drivers/net/wireless/ath/ar9170/phy.c
+++ b/drivers/net/wireless/ath/ar9170/phy.c
@@ -987,6 +987,124 @@  static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2)
 #undef SHIFT
 }
 
+static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array)
+{
+	int i;
+
+	for (i = 0; i < 3; i++)
+		if (x <= x_array[i + 1])
+			break;
+
+	return ar9170_interpolate_u8(x,
+				     x_array[i],
+				     y_array[i],
+				     x_array[i + 1],
+				     y_array[i + 1]);
+}
+
+static int ar9170_set_freq_cal_data(struct ar9170 *ar,
+				    struct ieee80211_channel *channel)
+{
+	u8 *cal_freq_pier;
+	u8 vpds[2][AR5416_PD_GAIN_ICEPTS];
+	u8 pwrs[2][AR5416_PD_GAIN_ICEPTS];
+	int chain, idx, i;
+	u8 f;
+
+	switch (channel->band) {
+	case IEEE80211_BAND_2GHZ:
+		f = channel->center_freq - 2300;
+		cal_freq_pier = ar->eeprom.cal_freq_pier_2G;
+		i = AR5416_NUM_2G_CAL_PIERS - 1;
+		break;
+
+	case IEEE80211_BAND_5GHZ:
+		f = (channel->center_freq - 4800) / 5;
+		cal_freq_pier = ar->eeprom.cal_freq_pier_5G;
+		i = AR5416_NUM_5G_CAL_PIERS - 1;
+		break;
+
+	default:
+		return -EINVAL;
+		break;
+	}
+
+	for (; i >= 0; i--) {
+		if (cal_freq_pier[i] != 0xff)
+			break;
+	}
+	if (i < 0)
+		return -EINVAL;
+
+	idx = ar9170_find_freq_idx(i, cal_freq_pier, f);
+
+	ar9170_regwrite_begin(ar);
+
+	for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) {
+		for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) {
+			struct ar9170_calibration_data_per_freq *cal_pier_data;
+			int j;
+
+			switch (channel->band) {
+			case IEEE80211_BAND_2GHZ:
+				cal_pier_data = &ar->eeprom.
+					cal_pier_data_2G[chain][idx];
+				break;
+
+			case IEEE80211_BAND_5GHZ:
+				cal_pier_data = &ar->eeprom.
+					cal_pier_data_5G[chain][idx];
+				break;
+
+			default:
+				return -EINVAL;
+			}
+
+			for (j = 0; j < 2; j++) {
+				vpds[j][i] = ar9170_interpolate_u8(f,
+					cal_freq_pier[idx],
+					cal_pier_data->vpd_pdg[j][i],
+					cal_freq_pier[idx + 1],
+					cal_pier_data[1].vpd_pdg[j][i]);
+
+				pwrs[j][i] = ar9170_interpolate_u8(f,
+					cal_freq_pier[idx],
+					cal_pier_data->pwr_pdg[j][i],
+					cal_freq_pier[idx + 1],
+					cal_pier_data[1].pwr_pdg[j][i]) / 2;
+			}
+		}
+
+		for (i = 0; i < 76; i++) {
+			u32 phy_data;
+			u8 tmp;
+
+			if (i < 25) {
+				tmp = ar9170_interpolate_val(i, &pwrs[0][0],
+							     &vpds[0][0]);
+			} else {
+				tmp = ar9170_interpolate_val(i - 12,
+							     &pwrs[1][0],
+							     &vpds[1][0]);
+			}
+
+			phy_data |= tmp << ((i & 3) << 3);
+			if ((i & 3) == 3) {
+				ar9170_regwrite(0x1c6280 + chain * 0x1000 +
+						(i & ~3), phy_data);
+				phy_data = 0;
+			}
+		}
+
+		for (i = 19; i < 32; i++)
+			ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2),
+					0x0);
+	}
+
+	ar9170_regwrite_finish();
+	return ar9170_regwrite_result();
+}
+
 static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
 {
 	struct ar9170_calibration_target_power_legacy *ctpl;
@@ -1207,6 +1325,10 @@  int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
 	if (err)
 		return err;
 
+	err = ar9170_set_freq_cal_data(ar, channel);
+	if (err)
+		return err;
+
 	err = ar9170_set_power_cal(ar, channel->center_freq, bw);
 	if (err)
 		return err;