Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH v2 06/20] rt2x00: rt2800lib: fix BBP1_TX_ANTENNA field configuration for 3T devices
From: Gabor Juhos @ 2013-07-01  7:47 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, users, Gabor Juhos
In-Reply-To: <1372664879-18474-1-git-send-email-juhosg@openwrt.org>

The field must be set to 2 instead of 0 for
devices with three TX chains.

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
 drivers/net/wireless/rt2x00/rt2800lib.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index b6f456c..6f6f48f 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1764,7 +1764,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
 			rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
 		break;
 	case 3:
-		rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
+		rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
 		break;
 	}
 
-- 
1.7.10


^ permalink raw reply related

* [PATCH v2 05/20] rt2x00: rt2800lib: add TX power configuration for RT3593
From: Gabor Juhos @ 2013-07-01  7:47 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, users, Gabor Juhos
In-Reply-To: <1372664879-18474-1-git-send-email-juhosg@openwrt.org>

Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629
driver.

References:
  RTMPReadTxPwrPerRateExt in chips/rt3593.c
  RT3593_AsicGetTxPowerOffset in chips/rt3593.c

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
 drivers/net/wireless/rt2x00/rt2800.h    |  116 +++++++++
 drivers/net/wireless/rt2x00/rt2800lib.c |  425 ++++++++++++++++++++++++++++++-
 2 files changed, 538 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 47aceae..7b7caeb 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -1083,6 +1083,15 @@
 #define TX_PWR_CFG_0_9MBS		FIELD32(0x00f00000)
 #define TX_PWR_CFG_0_12MBS		FIELD32(0x0f000000)
 #define TX_PWR_CFG_0_18MBS		FIELD32(0xf0000000)
+/* bits for 3T devices */
+#define TX_PWR_CFG_0_CCK1_CH0		FIELD32(0x0000000f)
+#define TX_PWR_CFG_0_CCK1_CH1		FIELD32(0x000000f0)
+#define TX_PWR_CFG_0_CCK5_CH0		FIELD32(0x00000f00)
+#define TX_PWR_CFG_0_CCK5_CH1		FIELD32(0x0000f000)
+#define TX_PWR_CFG_0_OFDM6_CH0		FIELD32(0x000f0000)
+#define TX_PWR_CFG_0_OFDM6_CH1		FIELD32(0x00f00000)
+#define TX_PWR_CFG_0_OFDM12_CH0		FIELD32(0x0f000000)
+#define TX_PWR_CFG_0_OFDM12_CH1		FIELD32(0xf0000000)
 
 /*
  * TX_PWR_CFG_1:
@@ -1096,6 +1105,15 @@
 #define TX_PWR_CFG_1_MCS1		FIELD32(0x00f00000)
 #define TX_PWR_CFG_1_MCS2		FIELD32(0x0f000000)
 #define TX_PWR_CFG_1_MCS3		FIELD32(0xf0000000)
+/* bits for 3T devices */
+#define TX_PWR_CFG_1_OFDM24_CH0		FIELD32(0x0000000f)
+#define TX_PWR_CFG_1_OFDM24_CH1		FIELD32(0x000000f0)
+#define TX_PWR_CFG_1_OFDM48_CH0		FIELD32(0x00000f00)
+#define TX_PWR_CFG_1_OFDM48_CH1		FIELD32(0x0000f000)
+#define TX_PWR_CFG_1_MCS0_CH0		FIELD32(0x000f0000)
+#define TX_PWR_CFG_1_MCS0_CH1		FIELD32(0x00f00000)
+#define TX_PWR_CFG_1_MCS2_CH0		FIELD32(0x0f000000)
+#define TX_PWR_CFG_1_MCS2_CH1		FIELD32(0xf0000000)
 
 /*
  * TX_PWR_CFG_2:
@@ -1109,6 +1127,15 @@
 #define TX_PWR_CFG_2_MCS9		FIELD32(0x00f00000)
 #define TX_PWR_CFG_2_MCS10		FIELD32(0x0f000000)
 #define TX_PWR_CFG_2_MCS11		FIELD32(0xf0000000)
+/* bits for 3T devices */
+#define TX_PWR_CFG_2_MCS4_CH0		FIELD32(0x0000000f)
+#define TX_PWR_CFG_2_MCS4_CH1		FIELD32(0x000000f0)
+#define TX_PWR_CFG_2_MCS6_CH0		FIELD32(0x00000f00)
+#define TX_PWR_CFG_2_MCS6_CH1		FIELD32(0x0000f000)
+#define TX_PWR_CFG_2_MCS8_CH0		FIELD32(0x000f0000)
+#define TX_PWR_CFG_2_MCS8_CH1		FIELD32(0x00f00000)
+#define TX_PWR_CFG_2_MCS10_CH0		FIELD32(0x0f000000)
+#define TX_PWR_CFG_2_MCS10_CH1		FIELD32(0xf0000000)
 
 /*
  * TX_PWR_CFG_3:
@@ -1122,6 +1149,15 @@
 #define TX_PWR_CFG_3_UKNOWN2		FIELD32(0x00f00000)
 #define TX_PWR_CFG_3_UKNOWN3		FIELD32(0x0f000000)
 #define TX_PWR_CFG_3_UKNOWN4		FIELD32(0xf0000000)
+/* bits for 3T devices */
+#define TX_PWR_CFG_3_MCS12_CH0		FIELD32(0x0000000f)
+#define TX_PWR_CFG_3_MCS12_CH1		FIELD32(0x000000f0)
+#define TX_PWR_CFG_3_MCS14_CH0		FIELD32(0x00000f00)
+#define TX_PWR_CFG_3_MCS14_CH1		FIELD32(0x0000f000)
+#define TX_PWR_CFG_3_STBC0_CH0		FIELD32(0x000f0000)
+#define TX_PWR_CFG_3_STBC0_CH1		FIELD32(0x00f00000)
+#define TX_PWR_CFG_3_STBC2_CH0		FIELD32(0x0f000000)
+#define TX_PWR_CFG_3_STBC2_CH1		FIELD32(0xf0000000)
 
 /*
  * TX_PWR_CFG_4:
@@ -1131,6 +1167,11 @@
 #define TX_PWR_CFG_4_UKNOWN6		FIELD32(0x000000f0)
 #define TX_PWR_CFG_4_UKNOWN7		FIELD32(0x00000f00)
 #define TX_PWR_CFG_4_UKNOWN8		FIELD32(0x0000f000)
+/* bits for 3T devices */
+#define TX_PWR_CFG_3_STBC4_CH0		FIELD32(0x0000000f)
+#define TX_PWR_CFG_3_STBC4_CH1		FIELD32(0x000000f0)
+#define TX_PWR_CFG_3_STBC6_CH0		FIELD32(0x00000f00)
+#define TX_PWR_CFG_3_STBC6_CH1		FIELD32(0x0000f000)
 
 /*
  * TX_PIN_CFG:
@@ -1452,6 +1493,81 @@
  */
 #define EXP_ACK_TIME			0x1380
 
+/* TX_PWR_CFG_5 */
+#define TX_PWR_CFG_5			0x1384
+#define TX_PWR_CFG_5_MCS16_CH0		FIELD32(0x0000000f)
+#define TX_PWR_CFG_5_MCS16_CH1		FIELD32(0x000000f0)
+#define TX_PWR_CFG_5_MCS16_CH2		FIELD32(0x00000f00)
+#define TX_PWR_CFG_5_MCS18_CH0		FIELD32(0x000f0000)
+#define TX_PWR_CFG_5_MCS18_CH1		FIELD32(0x00f00000)
+#define TX_PWR_CFG_5_MCS18_CH2		FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_6 */
+#define TX_PWR_CFG_6			0x1388
+#define TX_PWR_CFG_6_MCS20_CH0		FIELD32(0x0000000f)
+#define TX_PWR_CFG_6_MCS20_CH1		FIELD32(0x000000f0)
+#define TX_PWR_CFG_6_MCS20_CH2		FIELD32(0x00000f00)
+#define TX_PWR_CFG_6_MCS22_CH0		FIELD32(0x000f0000)
+#define TX_PWR_CFG_6_MCS22_CH1		FIELD32(0x00f00000)
+#define TX_PWR_CFG_6_MCS22_CH2		FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_0_EXT */
+#define TX_PWR_CFG_0_EXT		0x1390
+#define TX_PWR_CFG_0_EXT_CCK1_CH2	FIELD32(0x0000000f)
+#define TX_PWR_CFG_0_EXT_CCK5_CH2	FIELD32(0x00000f00)
+#define TX_PWR_CFG_0_EXT_OFDM6_CH2	FIELD32(0x000f0000)
+#define TX_PWR_CFG_0_EXT_OFDM12_CH2	FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_1_EXT */
+#define TX_PWR_CFG_1_EXT		0x1394
+#define TX_PWR_CFG_1_EXT_OFDM24_CH2	FIELD32(0x0000000f)
+#define TX_PWR_CFG_1_EXT_OFDM48_CH2	FIELD32(0x00000f00)
+#define TX_PWR_CFG_1_EXT_MCS0_CH2	FIELD32(0x000f0000)
+#define TX_PWR_CFG_1_EXT_MCS2_CH2	FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_2_EXT */
+#define TX_PWR_CFG_2_EXT		0x1398
+#define TX_PWR_CFG_2_EXT_MCS4_CH2	FIELD32(0x0000000f)
+#define TX_PWR_CFG_2_EXT_MCS6_CH2	FIELD32(0x00000f00)
+#define TX_PWR_CFG_2_EXT_MCS8_CH2	FIELD32(0x000f0000)
+#define TX_PWR_CFG_2_EXT_MCS10_CH2	FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_3_EXT */
+#define TX_PWR_CFG_3_EXT		0x139c
+#define TX_PWR_CFG_3_EXT_MCS12_CH2	FIELD32(0x0000000f)
+#define TX_PWR_CFG_3_EXT_MCS14_CH2	FIELD32(0x00000f00)
+#define TX_PWR_CFG_3_EXT_STBC0_CH2	FIELD32(0x000f0000)
+#define TX_PWR_CFG_3_EXT_STBC2_CH2	FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_4_EXT */
+#define TX_PWR_CFG_4_EXT		0x13a0
+#define TX_PWR_CFG_4_EXT_STBC4_CH2	FIELD32(0x0000000f)
+#define TX_PWR_CFG_4_EXT_STBC6_CH2	FIELD32(0x00000f00)
+
+/* TX_PWR_CFG_7 */
+#define TX_PWR_CFG_7			0x13d4
+#define TX_PWR_CFG_7_OFDM54_CH0		FIELD32(0x0000000f)
+#define TX_PWR_CFG_7_OFDM54_CH1		FIELD32(0x000000f0)
+#define TX_PWR_CFG_7_OFDM54_CH2		FIELD32(0x00000f00)
+#define TX_PWR_CFG_7_MCS7_CH0		FIELD32(0x000f0000)
+#define TX_PWR_CFG_7_MCS7_CH1		FIELD32(0x00f00000)
+#define TX_PWR_CFG_7_MCS7_CH2		FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_8 */
+#define TX_PWR_CFG_8			0x13d8
+#define TX_PWR_CFG_8_MCS15_CH0		FIELD32(0x0000000f)
+#define TX_PWR_CFG_8_MCS15_CH1		FIELD32(0x000000f0)
+#define TX_PWR_CFG_8_MCS15_CH2		FIELD32(0x00000f00)
+#define TX_PWR_CFG_8_MCS23_CH0		FIELD32(0x000f0000)
+#define TX_PWR_CFG_8_MCS23_CH1		FIELD32(0x00f00000)
+#define TX_PWR_CFG_8_MCS23_CH2		FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_9 */
+#define TX_PWR_CFG_9			0x13dc
+#define TX_PWR_CFG_9_STBC7_CH0		FIELD32(0x0000000f)
+#define TX_PWR_CFG_9_STBC7_CH1		FIELD32(0x000000f0)
+#define TX_PWR_CFG_9_STBC7_CH2		FIELD32(0x00000f00)
+
 /*
  * RX_FILTER_CFG: RX configuration register.
  */
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 87b7f94..b6f456c 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -3121,6 +3121,9 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
 	u8 eirp_txpower_criterion;
 	u8 reg_limit;
 
+	if (rt2x00_rt(rt2x00dev, RT3593))
+		return min_t(u8, txpower, 0xc);
+
 	if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags)) {
 		/*
 		 * Check if eirp txpower exceed txpower_limit.
@@ -3156,6 +3159,412 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
 	return min_t(u8, txpower, 0xc);
 }
 
+
+enum {
+	TX_PWR_CFG_0_IDX,
+	TX_PWR_CFG_1_IDX,
+	TX_PWR_CFG_2_IDX,
+	TX_PWR_CFG_3_IDX,
+	TX_PWR_CFG_4_IDX,
+	TX_PWR_CFG_5_IDX,
+	TX_PWR_CFG_6_IDX,
+	TX_PWR_CFG_7_IDX,
+	TX_PWR_CFG_8_IDX,
+	TX_PWR_CFG_9_IDX,
+	TX_PWR_CFG_0_EXT_IDX,
+	TX_PWR_CFG_1_EXT_IDX,
+	TX_PWR_CFG_2_EXT_IDX,
+	TX_PWR_CFG_3_EXT_IDX,
+	TX_PWR_CFG_4_EXT_IDX,
+	TX_PWR_CFG_IDX_COUNT,
+};
+
+static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev,
+					 struct ieee80211_channel *chan,
+					 int power_level)
+{
+	u8 txpower;
+	u16 eeprom;
+	u32 regs[TX_PWR_CFG_IDX_COUNT];
+	unsigned int offset;
+	enum ieee80211_band band = chan->band;
+	int delta;
+	int i;
+
+	memset(regs, '\0', sizeof(regs));
+
+	/* TODO: adapt TX power reduction from the rt28xx code */
+
+	/* calculate temperature compensation delta */
+	delta = rt2800_get_gain_calibration_delta(rt2x00dev);
+
+	if (band == IEEE80211_BAND_5GHZ)
+		offset = 16;
+	else
+		offset = 0;
+
+	if (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
+		offset += 8;
+
+	/* read the next four txpower values */
+	rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+				      offset, &eeprom);
+
+	/* CCK 1MBS,2MBS */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 1, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+			   TX_PWR_CFG_0_CCK1_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+			   TX_PWR_CFG_0_CCK1_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_EXT_IDX],
+			   TX_PWR_CFG_0_EXT_CCK1_CH2, txpower);
+
+	/* CCK 5.5MBS,11MBS */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 1, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+			   TX_PWR_CFG_0_CCK5_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+			   TX_PWR_CFG_0_CCK5_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_EXT_IDX],
+			   TX_PWR_CFG_0_EXT_CCK5_CH2, txpower);
+
+	/* OFDM 6MBS,9MBS */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+			   TX_PWR_CFG_0_OFDM6_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+			   TX_PWR_CFG_0_OFDM6_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_EXT_IDX],
+			   TX_PWR_CFG_0_EXT_OFDM6_CH2, txpower);
+
+	/* OFDM 12MBS,18MBS */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+			   TX_PWR_CFG_0_OFDM12_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+			   TX_PWR_CFG_0_OFDM12_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_0_EXT_IDX],
+			   TX_PWR_CFG_0_EXT_OFDM12_CH2, txpower);
+
+	/* read the next four txpower values */
+	rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+				      offset + 1, &eeprom);
+
+	/* OFDM 24MBS,36MBS */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+			   TX_PWR_CFG_1_OFDM24_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+			   TX_PWR_CFG_1_OFDM24_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_EXT_IDX],
+			   TX_PWR_CFG_1_EXT_OFDM24_CH2, txpower);
+
+	/* OFDM 48MBS */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+			   TX_PWR_CFG_1_OFDM48_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+			   TX_PWR_CFG_1_OFDM48_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_EXT_IDX],
+			   TX_PWR_CFG_1_EXT_OFDM48_CH2, txpower);
+
+	/* OFDM 54MBS */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+			   TX_PWR_CFG_7_OFDM54_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+			   TX_PWR_CFG_7_OFDM54_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+			   TX_PWR_CFG_7_OFDM54_CH2, txpower);
+
+	/* read the next four txpower values */
+	rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+				      offset + 2, &eeprom);
+
+	/* MCS 0,1 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+			   TX_PWR_CFG_1_MCS0_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+			   TX_PWR_CFG_1_MCS0_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_EXT_IDX],
+			   TX_PWR_CFG_1_EXT_MCS0_CH2, txpower);
+
+	/* MCS 2,3 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+			   TX_PWR_CFG_1_MCS2_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+			   TX_PWR_CFG_1_MCS2_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_1_EXT_IDX],
+			   TX_PWR_CFG_1_EXT_MCS2_CH2, txpower);
+
+	/* MCS 4,5 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+			   TX_PWR_CFG_2_MCS4_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+			   TX_PWR_CFG_2_MCS4_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_EXT_IDX],
+			   TX_PWR_CFG_2_EXT_MCS4_CH2, txpower);
+
+	/* MCS 6 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+			   TX_PWR_CFG_2_MCS6_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+			   TX_PWR_CFG_2_MCS6_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_EXT_IDX],
+			   TX_PWR_CFG_2_EXT_MCS6_CH2, txpower);
+
+	/* read the next four txpower values */
+	rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+				      offset + 3, &eeprom);
+
+	/* MCS 7 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+			   TX_PWR_CFG_7_MCS7_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+			   TX_PWR_CFG_7_MCS7_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+			   TX_PWR_CFG_7_MCS7_CH2, txpower);
+
+	/* MCS 8,9 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+			   TX_PWR_CFG_2_MCS8_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+			   TX_PWR_CFG_2_MCS8_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_EXT_IDX],
+			   TX_PWR_CFG_2_EXT_MCS8_CH2, txpower);
+
+	/* MCS 10,11 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+			   TX_PWR_CFG_2_MCS10_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+			   TX_PWR_CFG_2_MCS10_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_2_EXT_IDX],
+			   TX_PWR_CFG_2_EXT_MCS10_CH2, txpower);
+
+	/* MCS 12,13 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+			   TX_PWR_CFG_3_MCS12_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+			   TX_PWR_CFG_3_MCS12_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_EXT_IDX],
+			   TX_PWR_CFG_3_EXT_MCS12_CH2, txpower);
+
+	/* read the next four txpower values */
+	rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+				      offset + 4, &eeprom);
+
+	/* MCS 14 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+			   TX_PWR_CFG_3_MCS14_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+			   TX_PWR_CFG_3_MCS14_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_EXT_IDX],
+			   TX_PWR_CFG_3_EXT_MCS14_CH2, txpower);
+
+	/* MCS 15 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+			   TX_PWR_CFG_8_MCS15_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+			   TX_PWR_CFG_8_MCS15_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+			   TX_PWR_CFG_8_MCS15_CH2, txpower);
+
+	/* MCS 16,17 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+			   TX_PWR_CFG_5_MCS16_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+			   TX_PWR_CFG_5_MCS16_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+			   TX_PWR_CFG_5_MCS16_CH2, txpower);
+
+	/* MCS 18,19 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+			   TX_PWR_CFG_5_MCS18_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+			   TX_PWR_CFG_5_MCS18_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+			   TX_PWR_CFG_5_MCS18_CH2, txpower);
+
+	/* read the next four txpower values */
+	rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+				      offset + 5, &eeprom);
+
+	/* MCS 20,21 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+			   TX_PWR_CFG_6_MCS20_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+			   TX_PWR_CFG_6_MCS20_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+			   TX_PWR_CFG_6_MCS20_CH2, txpower);
+
+	/* MCS 22 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+			   TX_PWR_CFG_6_MCS22_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+			   TX_PWR_CFG_6_MCS22_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+			   TX_PWR_CFG_6_MCS22_CH2, txpower);
+
+	/* MCS 23 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+			   TX_PWR_CFG_8_MCS23_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+			   TX_PWR_CFG_8_MCS23_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+			   TX_PWR_CFG_8_MCS23_CH2, txpower);
+
+	/* read the next four txpower values */
+	rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+				      offset + 6, &eeprom);
+
+	/* STBC, MCS 0,1 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+			   TX_PWR_CFG_3_STBC0_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+			   TX_PWR_CFG_3_STBC0_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_EXT_IDX],
+			   TX_PWR_CFG_3_EXT_STBC0_CH2, txpower);
+
+	/* STBC, MCS 2,3 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+			   TX_PWR_CFG_3_STBC2_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+			   TX_PWR_CFG_3_STBC2_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_3_EXT_IDX],
+			   TX_PWR_CFG_3_EXT_STBC2_CH2, txpower);
+
+	/* STBC, MCS 4,5 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_4_EXT_IDX], TX_PWR_CFG_RATE0,
+			   txpower);
+
+	/* STBC, MCS 6 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE2, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE3, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_4_EXT_IDX], TX_PWR_CFG_RATE2,
+			   txpower);
+
+	/* read the next four txpower values */
+	rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+				      offset + 7, &eeprom);
+
+	/* STBC, MCS 7 */
+	txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+	txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+					    txpower, delta);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_9_IDX],
+			   TX_PWR_CFG_9_STBC7_CH0, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_9_IDX],
+			   TX_PWR_CFG_9_STBC7_CH1, txpower);
+	rt2x00_set_field32(&regs[TX_PWR_CFG_9_IDX],
+			   TX_PWR_CFG_9_STBC7_CH2, txpower);
+
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, regs[TX_PWR_CFG_0_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, regs[TX_PWR_CFG_1_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, regs[TX_PWR_CFG_2_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, regs[TX_PWR_CFG_3_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, regs[TX_PWR_CFG_4_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_5, regs[TX_PWR_CFG_5_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_6, regs[TX_PWR_CFG_6_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_7, regs[TX_PWR_CFG_7_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_8, regs[TX_PWR_CFG_8_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_9, regs[TX_PWR_CFG_9_IDX]);
+
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_0_EXT,
+			      regs[TX_PWR_CFG_0_EXT_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_1_EXT,
+			      regs[TX_PWR_CFG_1_EXT_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_2_EXT,
+			      regs[TX_PWR_CFG_2_EXT_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_3_EXT,
+			      regs[TX_PWR_CFG_3_EXT_IDX]);
+	rt2800_register_write(rt2x00dev, TX_PWR_CFG_4_EXT,
+			      regs[TX_PWR_CFG_4_EXT_IDX]);
+
+	for (i = 0; i < TX_PWR_CFG_IDX_COUNT; i++)
+		rt2x00_dbg(rt2x00dev,
+			   "band:%cGHz, BW:%c0MHz, TX_PWR_CFG_%d%s = %08lx\n",
+			   (band == IEEE80211_BAND_5GHZ) ? '5' : '2',
+			   (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) ?
+								'4' : '2',
+			   (i > TX_PWR_CFG_9_IDX) ?
+					(i - TX_PWR_CFG_9_IDX - 1) : i,
+			   (i > TX_PWR_CFG_9_IDX) ? "_EXT" : "",
+			   (unsigned long) regs[i]);
+}
+
 /*
  * We configure transmit power using MAC TX_PWR_CFG_{0,...,N} registers and
  * BBP R1 register. TX_PWR_CFG_X allow to configure per rate TX power values,
@@ -3165,9 +3574,9 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
  * EEPROM_TXPOWER_BYRATE offset. We adjust them and BBP R1 settings according to
  * current conditions (i.e. band, bandwidth, temperature, user settings).
  */
-static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
-				  struct ieee80211_channel *chan,
-				  int power_level)
+static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev,
+					 struct ieee80211_channel *chan,
+					 int power_level)
 {
 	u8 txpower, r1;
 	u16 eeprom;
@@ -3339,6 +3748,16 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
 	}
 }
 
+static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
+				  struct ieee80211_channel *chan,
+				  int power_level)
+{
+	if (rt2x00_rt(rt2x00dev, RT3593))
+		rt2800_config_txpower_rt3593(rt2x00dev, chan, power_level);
+	else
+		rt2800_config_txpower_rt28xx(rt2x00dev, chan, power_level);
+}
+
 void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev)
 {
 	rt2800_config_txpower(rt2x00dev, rt2x00dev->hw->conf.chandef.chan,
-- 
1.7.10


^ permalink raw reply related

* [PATCH v2 00/20] rt2x00: add experimental support for RT3593
From: Gabor Juhos @ 2013-07-01  7:47 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, users, Gabor Juhos

This patch-set implements experiemental support for the
RT3593 chipset. The patches are tested on the Linksys
AE3000 USB device only, however other USB devices which
are using the RT3573 chips might work as well.

The patch-set depends on the following series:
'rt2x00: rt2800lib: add support for extended EEPROM of three-cain devices'

Changes since v1:
 - add missing patch
 - make Linksys AE3000 support optional

Gabor Juhos (20):
  rt2x00: rt2800lib: add MAC register initialization for RT3593
  rt2x00: rt2800lib: add BBP register initialization for RT3593
  rt2x00: rt2800lib: add RFCSR register initialization for RT3593
  rt2x00: rt2800lib: add BBP post initialization for RT3593
  rt2x00: rt2800lib: add TX power configuration for RT3593
  rt2x00: rt2800lib: fix BBP1_TX_ANTENNA field configuration for 3T
    devices
  rt2x00: rt2800lib: fix antenna configuration for RT3593
  rt2x00: rt2800lib: add rt2800_txpower_to_dev helper
  rt2x00: rt2800lib: fix default TX power values for RT3593
  rt2x00: rt2800lib: introduce rt2800_get_txmixer_gain_{24,5}g helpers
  rt2x00: rt2800lib: hardcode TX mixer gain values for RT3593
  rt2x00: rt2x00lib: fix LNA_A[12] gain values for RT3593
  rt2x00: rt2800lib: add default_power3 field for three-chain devices
  rt2x00: rt2800lib: add rf_vals for RF3053
  rt2x00: rt2800lib: add channel configuration for RF3053
  rt2x00: rt2800lib: enable VCO recalibration for RF3053
  rt2x00: rt2800lib: enable RF3053 support
  rt2x00: rt2800lib: enable RT3593 support
  rt2x00: rt2800usb: use correct [RT]XWI size for RT3593
  rt2x00: rt2800usb: add USB device ID for Linksys AE3000

 drivers/net/wireless/rt2x00/Kconfig     |    6 +
 drivers/net/wireless/rt2x00/rt2800.h    |  187 ++++-
 drivers/net/wireless/rt2x00/rt2800lib.c | 1227 ++++++++++++++++++++++++++++++-
 drivers/net/wireless/rt2x00/rt2800usb.c |    9 +-
 drivers/net/wireless/rt2x00/rt2x00.h    |    1 +
 5 files changed, 1385 insertions(+), 45 deletions(-)

--
1.7.10


^ permalink raw reply

* [PATCH v2 04/20] rt2x00: rt2800lib: add BBP post initialization for RT3593
From: Gabor Juhos @ 2013-07-01  7:47 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, users, Gabor Juhos
In-Reply-To: <1372664879-18474-1-git-send-email-juhosg@openwrt.org>

Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629
driver.

Reference:
  RT3593_PostBBPInitialization in chips/rt3553.c

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
 drivers/net/wireless/rt2x00/rt2800lib.c |   48 ++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 0041b2c..87b7f94 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -5382,6 +5382,52 @@ static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev)
 	rt2800_normal_mode_setup_3xxx(rt2x00dev);
 }
 
+static void rt3593_post_bbp_init(struct rt2x00_dev *rt2x00dev)
+{
+	u8 bbp;
+	bool txbf_enabled = false; /* FIXME */
+
+	rt2800_bbp_read(rt2x00dev, 105, &bbp);
+	if (rt2x00dev->default_ant.rx_chain_num == 1)
+		rt2x00_set_field8(&bbp, BBP105_MLD, 0);
+	else
+		rt2x00_set_field8(&bbp, BBP105_MLD, 1);
+	rt2800_bbp_write(rt2x00dev, 105, bbp);
+
+	rt2800_bbp4_mac_if_ctrl(rt2x00dev);
+
+	rt2800_bbp_write(rt2x00dev, 92, 0x02);
+	rt2800_bbp_write(rt2x00dev, 82, 0x82);
+	rt2800_bbp_write(rt2x00dev, 106, 0x05);
+	rt2800_bbp_write(rt2x00dev, 104, 0x92);
+	rt2800_bbp_write(rt2x00dev, 88, 0x90);
+	rt2800_bbp_write(rt2x00dev, 148, 0xc8);
+	rt2800_bbp_write(rt2x00dev, 47, 0x48);
+	rt2800_bbp_write(rt2x00dev, 120, 0x50);
+
+	if (txbf_enabled)
+		rt2800_bbp_write(rt2x00dev, 163, 0xbd);
+	else
+		rt2800_bbp_write(rt2x00dev, 163, 0x9d);
+
+	/* SNR mapping */
+	rt2800_bbp_write(rt2x00dev, 142, 6);
+	rt2800_bbp_write(rt2x00dev, 143, 160);
+	rt2800_bbp_write(rt2x00dev, 142, 7);
+	rt2800_bbp_write(rt2x00dev, 143, 161);
+	rt2800_bbp_write(rt2x00dev, 142, 8);
+	rt2800_bbp_write(rt2x00dev, 143, 162);
+
+	/* ADC/DAC control */
+	rt2800_bbp_write(rt2x00dev, 31, 0x08);
+
+	/* RX AGC energy lower bound in log2 */
+	rt2800_bbp_write(rt2x00dev, 68, 0x0b);
+
+	/* FIXME: BBP 105 owerwrite? */
+	rt2800_bbp_write(rt2x00dev, 105, 0x04);
+}
+
 static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev)
 {
 	struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
@@ -5460,7 +5506,7 @@ static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev)
 	rt2800_led_open_drain_enable(rt2x00dev);
 	rt2800_normal_mode_setup_3593(rt2x00dev);
 
-	/* TODO: post BBP initialization */
+	rt3593_post_bbp_init(rt2x00dev);
 
 	/* TODO: enable stream mode support */
 }
-- 
1.7.10


^ permalink raw reply related

* [PATCH v2 01/20] rt2x00: rt2800lib: add MAC register initialization for RT3593
From: Gabor Juhos @ 2013-07-01  7:47 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, users, Gabor Juhos
In-Reply-To: <1372664879-18474-1-git-send-email-juhosg@openwrt.org>

Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629
driver.

Reference:
  NICInitRT3593MacRegisters in chips/rt3593.c

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
 drivers/net/wireless/rt2x00/rt2800.h    |    1 +
 drivers/net/wireless/rt2x00/rt2800lib.c |   17 +++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 9216834..02bc80d 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -88,6 +88,7 @@
 #define REV_RT3071E			0x0211
 #define REV_RT3090E			0x0211
 #define REV_RT3390E			0x0211
+#define REV_RT3593E			0x0211
 #define REV_RT5390F			0x0502
 #define REV_RT5390R			0x1502
 #define REV_RT5592C			0x0221
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 7b216f9..6f58ceb 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -3715,6 +3715,23 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 	} else if (rt2x00_rt(rt2x00dev, RT3572)) {
 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
+	} else if (rt2x00_rt(rt2x00dev, RT3593)) {
+		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000402);
+		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
+		if (rt2x00_rt_rev_lt(rt2x00dev, RT3593, REV_RT3593E)) {
+			rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1,
+					   &eeprom);
+			if (rt2x00_get_field16(eeprom,
+					       EEPROM_NIC_CONF1_DAC_TEST))
+				rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+						      0x0000001f);
+			else
+				rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+						      0x0000000f);
+		} else {
+			rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+					      0x00000000);
+		}
 	} else if (rt2x00_rt(rt2x00dev, RT5390) ||
 		   rt2x00_rt(rt2x00dev, RT5392) ||
 		   rt2x00_rt(rt2x00dev, RT5592)) {
-- 
1.7.10


^ permalink raw reply related

* [PATCH v2 02/20] rt2x00: rt2800lib: add BBP register initialization for RT3593
From: Gabor Juhos @ 2013-07-01  7:47 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, users, Gabor Juhos
In-Reply-To: <1372664879-18474-1-git-send-email-juhosg@openwrt.org>

Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629
driver.

References:
  NICInitRT3593BbpRegisters in chips/rt3593.c
  NICInitBBP in common/rtmp_init.c
  NICInitAsicFromEEPROM in common/rtmp_init.c

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
 drivers/net/wireless/rt2x00/rt2800lib.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 6f58ceb..32ecd1a 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -4505,6 +4505,22 @@ static void rt2800_init_bbp_3572(struct rt2x00_dev *rt2x00dev)
 	rt2800_disable_unused_dac_adc(rt2x00dev);
 }
 
+static void rt2800_init_bbp_3593(struct rt2x00_dev *rt2x00dev)
+{
+	rt2800_init_bbp_early(rt2x00dev);
+
+	rt2800_bbp_write(rt2x00dev, 79, 0x13);
+	rt2800_bbp_write(rt2x00dev, 80, 0x05);
+	rt2800_bbp_write(rt2x00dev, 81, 0x33);
+	rt2800_bbp_write(rt2x00dev, 137, 0x0f);
+
+	rt2800_bbp_write(rt2x00dev, 84, 0x19);
+
+	/* Enable DC filter */
+	if (rt2x00_rt_rev_gte(rt2x00dev, RT3593, REV_RT3593E))
+		rt2800_bbp_write(rt2x00dev, 103, 0xc0);
+}
+
 static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
 {
 	int ant, div_mode;
@@ -4720,6 +4736,9 @@ static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 	case RT3572:
 		rt2800_init_bbp_3572(rt2x00dev);
 		break;
+	case RT3593:
+		rt2800_init_bbp_3593(rt2x00dev);
+		return;
 	case RT5390:
 	case RT5392:
 		rt2800_init_bbp_53xx(rt2x00dev);
-- 
1.7.10


^ permalink raw reply related

* Re: [rt2x00-users] [PATCH 00/19] rt2x00: add experimental support for RT3593
From: Gabor Juhos @ 2013-07-01  7:43 UTC (permalink / raw)
  To: Andreas Hartmann; +Cc: John Linville, linux-wireless, users
In-Reply-To: <20130629170409.5df177d5@dualc.maya.org>

Hi Andreas,

> Gabor Juhos wrote:
>> This patch-set implements experiemental support for the
>> RT3593 chipset. The patches are tested on the Linksys
>> AE3000 USB device only, however other USB devices which
>> are using the RT3573 chips might work as well.
> 
> 
> I tested your patchset (and all the others) with the same device you
> used for developing in a real life scenario. My AP
> http://wikidevi.com/wiki/TP-LINK_TL-WDN4800 is configured for 2.4 GHz,
> 40MHz, 802.11n, EAP-TLS.
> 
> The AE3000 is used with a notebook / core i5 processor.
> 
> The test was done *during a parallel running full hd video* in the
> same net with another AE3000 running on raspberry pi with ralinks own
> driver *always w/o any stuttering* (that's why I'm buying such devices)!
> There is a reinforced-concrete floor between AP and the STAs.
> 
> From /var/log/messages:
> 
> kernel: [33425.890174] cfg80211: Calling CRDA to update world regulatory domain
> kernel: [33425.894221] cfg80211: World regulatory domain updated:
> kernel: [33425.894230] cfg80211:   (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
> kernel: [33425.894232] cfg80211:   (2402000 KHz - 2472000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
> kernel: [33425.894234] cfg80211:   (2457000 KHz - 2482000 KHz @ 20000 KHz), (300 mBi, 2000 mBm)
> kernel: [33425.894236] cfg80211:   (2474000 KHz - 2494000 KHz @ 20000 KHz), (300 mBi, 2000 mBm)
> kernel: [33425.894238] cfg80211:   (5170000 KHz - 5250000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
> kernel: [33425.894240] cfg80211:   (5735000 KHz - 5835000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
> kernel: [33425.973578] usb 2-1.5: reset high-speed USB device number 3 using ehci-pci
> kernel: [33426.070273] ieee80211 phy0: rt2x00_set_rt: Info - RT chipset 3593, rev 0402 detected
> kernel: [33426.102833] ieee80211 phy0: rt2x00_set_rf: Info - RF chipset 000d detected
> kernel: [33426.103387] ieee80211 phy0: Selected rate control algorithm 'minstrel_ht'
> kernel: [33426.104122] usbcore: registered new interface driver rt2800usb
> kernel: [33429.115258] ieee80211 phy0: rt2x00lib_request_firmware: Info - Loading firmware file 'rt2870.bin'
> kernel: [33429.115305] ieee80211 phy0: rt2x00lib_request_firmware: Info - Firmware detected - version: 0.33
> kernel: [33429.359196] IPv6: ADDRCONF(NETDEV_UP): wlan2: link is not ready
> kernel: [33432.884764] wlan2: authenticate with 11:22:33:44:55:66
> kernel: [33432.937069] wlan2: send auth to 11:22:33:44:55:66 (try 1/3)
> kernel: [33432.939615] wlan2: authenticated
> kernel: [33432.940177] wlan2: associate with 11:22:33:44:55:66 (try 1/3)
> kernel: [33432.943876] wlan2: RX AssocResp from 11:22:33:44:55:66 (capab=0x431 status=0 aid=1)
> kernel: [33432.953244] wlan2: associated
> kernel: [33432.953278] IPv6: ADDRCONF(NETDEV_CHANGE): wlan2: link becomes ready
> kernel: [33432.953322] cfg80211: Calling CRDA for country: DE
> kernel: [33432.957301] cfg80211: Regulatory domain changed to country: DE
> kernel: [33432.957306] cfg80211:   (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
> kernel: [33432.957310] cfg80211:   (2400000 KHz - 2483500 KHz @ 40000 KHz), (N/A, 2000 mBm)
> kernel: [33432.957313] cfg80211:   (5150000 KHz - 5250000 KHz @ 40000 KHz), (N/A, 2000 mBm)
> kernel: [33432.957316] cfg80211:   (5250000 KHz - 5350000 KHz @ 40000 KHz), (N/A, 2000 mBm)
> kernel: [33432.957319] cfg80211:   (5470000 KHz - 5725000 KHz @ 40000 KHz), (N/A, 2698 mBm)
> 
> 
> netperf gives with rt2800usb on the notebook:
> 
> MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to server () port 0 AF_INET : demo
> enable_enobufs failed: setsockopt
> Recv   Send    Send                          
> Socket Socket  Message  Elapsed              
> Size   Size    Size     Time     Throughput  
> bytes  bytes   bytes    secs.    10^6bits/sec  
> 
>  87380  16384  16384    10.01      78.41   
> MIGRATED TCP MAERTS TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET from server () port 0 AF_INET : demo
> enable_enobufs failed: setsockopt
> Recv   Send    Send                          
> Socket Socket  Message  Elapsed              
> Size   Size    Size     Time     Throughput  
> bytes  bytes   bytes    secs.    10^6bits/sec  
> 
>  87380  16384  16384    10.00     115.92   
> TCP SENDFILE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to server () port 0 AF_INET : demo
> Recv   Send    Send                          
> Socket Socket  Message  Elapsed              
> Size   Size    Size     Time     Throughput  
> bytes  bytes   bytes    secs.    10^6bits/sec  
> 
>  87380  16384  16384    10.02      86.46
> 
> 
> 
> The exactly same (=unchanged conditions) done with
> DPO_RT5572_LinuxSTA_2.6.1.3_20121022 on the notebook gives:
> 
> 
> MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to server () port 0 AF_INET : demo
> enable_enobufs failed: setsockopt
> Recv   Send    Send                          
> Socket Socket  Message  Elapsed              
> Size   Size    Size     Time     Throughput  
> bytes  bytes   bytes    secs.    10^6bits/sec  
> 
>  87380  16384  16384    10.02     130.36   
> MIGRATED TCP MAERTS TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET from server () port 0 AF_INET : demo
> enable_enobufs failed: setsockopt
> Recv   Send    Send                          
> Socket Socket  Message  Elapsed              
> Size   Size    Size     Time     Throughput  
> bytes  bytes   bytes    secs.    10^6bits/sec  
> 
>  87380  16384  16384    10.00     131.23   
> TCP SENDFILE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to server () port 0 AF_INET : demo
> Recv   Send    Send                          
> Socket Socket  Message  Elapsed              
> Size   Size    Size     Time     Throughput  
> bytes  bytes   bytes    secs.    10^6bits/sec  
> 
>  87380  16384  16384    10.03     131.33

Thank you for the test results. I have tested the device in managed mode against
various APs. To be honest, those were connectivity tests mainly, I did not run
throughput tests so far. I will do that later.

Regards,
Gabor

^ permalink raw reply

* Re: kernel panic on 3.10.0-rc7
From: Sedat Dilek @ 2013-07-01  7:37 UTC (permalink / raw)
  To: peizhao.research; +Cc: linux-wireless
In-Reply-To: <51D127E4.2080803@gmail.com>

On Mon, Jul 1, 2013 at 8:55 AM, Peizhao Hu <peizhao.research@gmail.com> wrote:
> Hi,
>
> Is there anyone has the same problem with me? I have a cm9 radio card with
> the node.
>
> The kernel compiled and booted alright, but crashed short after I set it up
> in the ad hoc mode. From the debug message output, it looks like something
> wrong with the rate control mechanism when it is trying to the rate
> (minstreal_get_rate function in this case).
>
> Is this a bug?
>
> Kernel version
> 3.10.0-rc7
>

Please, always add your kernel-config and some outputs like dmesg and
lspci/lsusb for better understanding.
2nd, try v3.10 (released a few hours ago)... There were wireless
patches pushed after v3.10-rc7.
Then report again.

- Sedat -

[1] Please, check docs sites on <wireless.git.org> on how-to report
wireless issues.

> root@alix-router:~# i[  250.809354] BUG: unable to handle kernel NULL
> pointe8
> [  250.812875] IP: [<d0952afa>] minstrel_get_rate+0x1a/0x220 [mac80211]
> [  250.812875] *pde = 00000000
> [  250.812875] Oops: 0000 [#1] SMP
> [  250.812875] Modules linked in: ath5k ath mac80211 cfg80211 arc4
> gpio_cs55]
> [  250.812875] CPU: 0 PID: 6 Comm: kworker/u2:0 Not tainted 3.10.0-rc7-cca+
> 1
> [  250.812875] Workqueue: phy0 ieee80211_iface_work [mac80211]
> [  250.812875] task: c002bfc0 ti: c0076000 task.ti: c0076000
> [  250.812875] EIP: 0060:[<d0952afa>] EFLAGS: 00010292 CPU: 0
> [  250.812875] EIP is at minstrel_get_rate+0x1a/0x220 [mac80211]
> [  250.812875] EAX: 00000000 EBX: 00000000 ECX: 00000000 EDX: cc2bf1c0
> [  250.812875] ESI: ce6cf900 EDI: c0077d00 EBP: c0077cac ESP: c0077c94
> [  250.812875]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
> [  250.812875] CR0: 8005003b CR2: 00000038 CR3: 0c245000 CR4: 00000090
> [  250.812875] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
> [  250.812875] DR6: ffff0ff0 DR7: 00000400
> [  250.812875] Stack:
> [  250.812875]  00017901 cc101500 00000180 cc133500 d0967920 cc2bf1e1
> c0077cd
> [  250.812875]  c0077d00 00000180 ce525170 00000000 cc2bf1e0 c0077d00
> cc2bf10
> [  250.812875]  c0077d24 c0077d30 d0927651 c02c5550 c0077cec d092001c
> cc1335c
> [  250.812875] Call Trace:
> [  250.812875]  [<d091a8dd>] rate_control_get_rate+0x9d/0xe0 [mac80211]
> [  250.812875]  [<d0927651>] ieee80211_beacon_get_tim+0x1a1/0x330 [mac80211]
> [  250.812875]  [<d092001c>] ? ieee80211_assign_beacon+0x1bc/0x1c0
> [mac80211]
> [  250.812875]  [<d0da3fb9>] ath5k_beacon_update+0x29/0x340 [ath5k]
> [  250.812875]  [<d0d99366>] ? ath5k_hw_get_frame_duration+0xa6/0xc0 [ath5k]
> [  250.812875]  [<d0d99140>] ? ath5k_hw_set_ifs_intervals+0x110/0x1b0
> [ath5k]
> [  250.812875]  [<d0da92d3>] ath5k_bss_info_changed+0x113/0x1f0 [ath5k]
> [  250.812875]  [<d0da91c0>] ? ath5k_configure_filter+0x1c0/0x1c0 [ath5k]
> [  250.812875]  [<d0908903>] ieee80211_bss_info_change_notify+0xc3/0x1c0
> [ma]
> [  250.812875]  [<d09141db>] ? __ieee80211_sta_join_ibss+0x19b/0x660
> [mac802]
> [  250.812875]  [<d091442c>] __ieee80211_sta_join_ibss+0x3ec/0x660
> [mac80211]
> [  250.812875]  [<c157be33>] ? printk+0x4d/0x4f
> [  250.812875]  [<d0915b4d>] ieee80211_ibss_work+0x31d/0x3d0 [mac80211]
> [  250.812875]  [<d0916d2d>] ieee80211_iface_work+0x18d/0x310 [mac80211]
> [  250.812875]  [<c105025f>] process_one_work+0x10f/0x380
> [  250.812875]  [<c104e485>] ? start_worker+0x25/0x30
> [  250.812875]  [<c1051000>] ? manage_workers.isra.24+0x180/0x290
> [  250.812875]  [<c105120a>] worker_thread+0xfa/0x310
> [  250.812875]  [<c1051110>] ? manage_workers.isra.24+0x290/0x290
> [  250.812875]  [<c1056674>] kthread+0x94/0xa0
> [  250.812875]  [<c158b1f7>] ret_from_kernel_thread+0x1b/0x28
> [  250.812875]  [<c10565e0>] ? flush_kthread_worker+0x90/0x90
> [  250.812875] Code: 3d fe 93 f0 5d c3 90 90 90 90 90 90 90 90 90 90 90 55
> 88
> [  250.812875] EIP: [<d0952afa>] minstrel_get_rate+0x1a/0x220 [mac80211]
> SS:4
> [  250.812875] CR2: 0000000000000038
> [  250.815950] ---[ end trace 87b8337e77cb6664 ]---
> [  250.817834] Kernel panic - not syncing: Fatal exception in interrupt
>
>
>
> --
> Regards;
>
> Peizhao
>
> --
> 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

^ permalink raw reply

* RE: [PATCH V2] vlan priority handling in WMM
From: voncken @ 2013-07-01  7:25 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless
In-Reply-To: <1372319520-29087-1-git-send-email-cedric.voncken@acksys.fr>

Any comments on this patch ? 

Cedric


-----Message d'origine-----
De : linux-wireless-owner@vger.kernel.org
[mailto:linux-wireless-owner@vger.kernel.org] De la part de
cedric.voncken@acksys.fr
Envoyé : jeudi 27 juin 2013 09:52
À : johannes@sipsolutions.net
Cc : linux-wireless@vger.kernel.org; cedric voncken
Objet : [PATCH V2] vlan priority handling in WMM

From: cedric voncken <cedric.voncken@acksys.fr>

If the VLAN tci is set in skb->vlan_tci use the priority field to determine
the WMM priority.

V2 modifications :
	Fix indentation
	Use symbolic constant
	include the header linux/if_vlan.h

Signed-off-by: cedric Voncken <cedric.voncken@acksys.fr>
---
 net/wireless/util.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/net/wireless/util.c b/net/wireless/util.c index
74458b7..13937db 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -10,6 +10,7 @@
 #include <net/cfg80211.h>
 #include <net/ip.h>
 #include <net/dsfield.h>
+#include <linux/if_vlan.h>
 #include "core.h"
 #include "rdev-ops.h"
 
@@ -685,6 +686,7 @@ EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
 unsigned int cfg80211_classify8021d(struct sk_buff *skb)  {
 	unsigned int dscp;
+	unsigned char vlan_priority;
 
 	/* skb->priority values from 256->263 are magic values to
 	 * directly indicate a specific 802.1d priority.  This is used @@
-694,6 +696,10 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
 	if (skb->priority >= 256 && skb->priority <= 263)
 		return skb->priority - 256;
 
+	vlan_priority = (skb->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
+	if (vlan_priority > 0)
+		return vlan_priority;
+
 	switch (skb->protocol) {
 	case htons(ETH_P_IP):
 		dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc;
--
1.7.2.5

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


^ permalink raw reply

* kernel panic on 3.10.0-rc7
From: Peizhao Hu @ 2013-07-01  6:55 UTC (permalink / raw)
  To: linux-wireless

Hi,

Is there anyone has the same problem with me? I have a cm9 radio card 
with the node.

The kernel compiled and booted alright, but crashed short after I set it 
up in the ad hoc mode. From the debug message output, it looks like 
something wrong with the rate control mechanism when it is trying to the 
rate (minstreal_get_rate function in this case).

Is this a bug?

Kernel version
3.10.0-rc7

root@alix-router:~# i[  250.809354] BUG: unable to handle kernel NULL 
pointe8
[  250.812875] IP: [<d0952afa>] minstrel_get_rate+0x1a/0x220 [mac80211]
[  250.812875] *pde = 00000000
[  250.812875] Oops: 0000 [#1] SMP
[  250.812875] Modules linked in: ath5k ath mac80211 cfg80211 arc4 
gpio_cs55]
[  250.812875] CPU: 0 PID: 6 Comm: kworker/u2:0 Not tainted 
3.10.0-rc7-cca+ 1
[  250.812875] Workqueue: phy0 ieee80211_iface_work [mac80211]
[  250.812875] task: c002bfc0 ti: c0076000 task.ti: c0076000
[  250.812875] EIP: 0060:[<d0952afa>] EFLAGS: 00010292 CPU: 0
[  250.812875] EIP is at minstrel_get_rate+0x1a/0x220 [mac80211]
[  250.812875] EAX: 00000000 EBX: 00000000 ECX: 00000000 EDX: cc2bf1c0
[  250.812875] ESI: ce6cf900 EDI: c0077d00 EBP: c0077cac ESP: c0077c94
[  250.812875]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
[  250.812875] CR0: 8005003b CR2: 00000038 CR3: 0c245000 CR4: 00000090
[  250.812875] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
[  250.812875] DR6: ffff0ff0 DR7: 00000400
[  250.812875] Stack:
[  250.812875]  00017901 cc101500 00000180 cc133500 d0967920 cc2bf1e1 
c0077cd
[  250.812875]  c0077d00 00000180 ce525170 00000000 cc2bf1e0 c0077d00 
cc2bf10
[  250.812875]  c0077d24 c0077d30 d0927651 c02c5550 c0077cec d092001c 
cc1335c
[  250.812875] Call Trace:
[  250.812875]  [<d091a8dd>] rate_control_get_rate+0x9d/0xe0 [mac80211]
[  250.812875]  [<d0927651>] ieee80211_beacon_get_tim+0x1a1/0x330 [mac80211]
[  250.812875]  [<d092001c>] ? ieee80211_assign_beacon+0x1bc/0x1c0 
[mac80211]
[  250.812875]  [<d0da3fb9>] ath5k_beacon_update+0x29/0x340 [ath5k]
[  250.812875]  [<d0d99366>] ? ath5k_hw_get_frame_duration+0xa6/0xc0 [ath5k]
[  250.812875]  [<d0d99140>] ? ath5k_hw_set_ifs_intervals+0x110/0x1b0 
[ath5k]
[  250.812875]  [<d0da92d3>] ath5k_bss_info_changed+0x113/0x1f0 [ath5k]
[  250.812875]  [<d0da91c0>] ? ath5k_configure_filter+0x1c0/0x1c0 [ath5k]
[  250.812875]  [<d0908903>] ieee80211_bss_info_change_notify+0xc3/0x1c0 
[ma]
[  250.812875]  [<d09141db>] ? __ieee80211_sta_join_ibss+0x19b/0x660 
[mac802]
[  250.812875]  [<d091442c>] __ieee80211_sta_join_ibss+0x3ec/0x660 
[mac80211]
[  250.812875]  [<c157be33>] ? printk+0x4d/0x4f
[  250.812875]  [<d0915b4d>] ieee80211_ibss_work+0x31d/0x3d0 [mac80211]
[  250.812875]  [<d0916d2d>] ieee80211_iface_work+0x18d/0x310 [mac80211]
[  250.812875]  [<c105025f>] process_one_work+0x10f/0x380
[  250.812875]  [<c104e485>] ? start_worker+0x25/0x30
[  250.812875]  [<c1051000>] ? manage_workers.isra.24+0x180/0x290
[  250.812875]  [<c105120a>] worker_thread+0xfa/0x310
[  250.812875]  [<c1051110>] ? manage_workers.isra.24+0x290/0x290
[  250.812875]  [<c1056674>] kthread+0x94/0xa0
[  250.812875]  [<c158b1f7>] ret_from_kernel_thread+0x1b/0x28
[  250.812875]  [<c10565e0>] ? flush_kthread_worker+0x90/0x90
[  250.812875] Code: 3d fe 93 f0 5d c3 90 90 90 90 90 90 90 90 90 90 90 
55 88
[  250.812875] EIP: [<d0952afa>] minstrel_get_rate+0x1a/0x220 [mac80211] 
SS:4
[  250.812875] CR2: 0000000000000038
[  250.815950] ---[ end trace 87b8337e77cb6664 ]---
[  250.817834] Kernel panic - not syncing: Fatal exception in interrupt



--
Regards;

Peizhao


^ permalink raw reply

* Re: [PATCH 00/40] crda: reglib enhancements
From: Luis R. Rodriguez @ 2013-06-30 23:08 UTC (permalink / raw)
  To: wireless-regdb@lists.infradead.org, Ben Hutchings, alexandre
  Cc: linux-wireless, Luis R. Rodriguez
In-Reply-To: <1369966169-23640-1-git-send-email-mcgrof@do-not-panic.com>

On Thu, May 30, 2013 at 7:08 PM, Luis R. Rodriguez
<mcgrof@do-not-panic.com> wrote:
> From: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
>
> I've hinted I've been working towards a regdb regulatory
> library. This pushes that idea further as I was inclined
> recently to develop a union algorithm and saw we still
> had quite a bit of work to be able to share more consistently.
>
> I'll likely be using the intersection code as basis for this
> and as such I've cleaned that up and also ran valgrind over
> most of the code. I believe I've fixed all reglib memory
> related issues the rest of things valgrind bitches about
> are due to netlink.
>
> mcgrof@frijol ~ $ cat .valgrindrc
> --memcheck:leak-check=full
> --memcheck:leak-resolution=high
> --memcheck:show-reachable=yes
> --memcheck:num-callers=50
>
> If this looks OK I'll next start working towards the union
> code. The purpose of this is two fold:
>
> Help build regulatory domains out of arbitrary custom
> regulatory definitions and to also allow us to build
> more thorough world regulatory domains that have passive
> scan flags on regulatory rules that are do not fit the
> intersection.
>
> Luis R. Rodriguez (40):
>   crda: make reg_rules_intersect() style match Linux
>   crda: port over Linux is_valid_reg_rule() change bd05f28e
>   crda: remove verbose errors out of regdom_intersect()
>   crda: constify usage of struct ieee80211_regdomain
>   crda: remove unused BUG_ON() from intersect.c
>   crda: move regdom_intersect() to reglib
>   crda: fix regression when using reglib_for_each_country()
>   crda: move intersection if first attempt failed
>   crda: do not double count on reglib_for_each_country()
>   crda: annotate intersection worst case scenerio
>   crda: fix intersect.c memory management
>   crda: explicitly munmap() on reglib_get_rd_alpha2()
>   crda: explicitly close file descriptor and munmap() on failures
>   crda: separate crda_verify_db_signature() implementations
>   crda: use gcry_sexp_release() on crda_verify_db_signature()
>   crda: explicitly use close() and munmap() on reglib_get_rd_alpha2()
>   crda: use gcry_mpi_release() when using gcry_mpi_scan()
>   crda: rename world and prev_world on intersect.c
>   crda: remove verbosity out of intersect.c
>   crda: rename regdom_intersect() to reglib_intersect_rds()
>   crda: rename crda_get_file_ptr() to reglib_get_file_ptr()
>   crda: rename crda_verify_db_signature() to
>     reglib_verify_db_signature()
>   crda: rename print_regdom() to reglib_print_regdom()
>   crda: add regdb_dfs_regions
>   crda: make print-regdom use internal flags
>   crda: move reg print helpers to reglib
>   crda: rename is_world_regdom() to reglib_is_world_regdom()
>   crda: rename isalpha_upper() to reglib_isalpha_upper()
>   crda: rename is_alpha2() to reglib_is_alpha2()
>   crda: rename is_valid_regdom() to reglib_is_valid_regdom()
>   crda: rename max() to reglib_max()
>   crda: rename min() to reglib_min()
>   crda: fix spacing on reglib_for_each_country()
>   crda: clarify intersect.c only computes an intersection
>   crda: separate intersecting a full db into a helper
>   crda: move reglib_intersect_regdb() to reglib
>   crda: move regdbprint to its own helper
>   crda: add reglib regdb context helpers:
>     reglib_(malloc|free)_regdb_ctx()
>   crda: pass struct reglib_regdb_ctx to country2rd()
>   crda: make reglib_for_each_country() use the reglib context
>
>  Makefile       |    4 +-
>  crda.c         |   14 +-
>  intersect.c    |  264 ++---------------------------
>  print-regdom.c |   81 ---------
>  regdb.h        |   24 ++-
>  regdbdump.c    |   30 +++-
>  reglib.c       |  518 +++++++++++++++++++++++++++++++++++++++++++++-----------
>  reglib.h       |  125 +++++++++++---
>  8 files changed, 589 insertions(+), 471 deletions(-)
>  delete mode 100644 print-regdom.c

I've applied and pushed these given I saw no opposition. Please let me
know if you run into any issues. I may cut a new release soon but I
have a few other ideas I was considering implementing.

  Luis

^ permalink raw reply

* [PATCH] ath9k: fix tx pending frames accounting for dropped packets
From: Felix Fietkau @ 2013-06-30 10:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville

When dropping packets that have gone far enough into the tx path, the
pending frame counter needs to be decreased.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/xmit.c | 44 ++++++++++++++++++++++-------------
 1 file changed, 28 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index c59ae43..9279927 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -146,6 +146,28 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
 			       ARRAY_SIZE(bf->rates));
 }
 
+static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
+			     struct sk_buff *skb)
+{
+	int q;
+
+	q = skb_get_queue_mapping(skb);
+	if (txq == sc->tx.uapsdq)
+		txq = sc->tx.txq_map[q];
+
+	if (txq != sc->tx.txq_map[q])
+		return;
+
+	if (WARN_ON(--txq->pending_frames < 0))
+		txq->pending_frames = 0;
+
+	if (txq->stopped &&
+	    txq->pending_frames < sc->tx.txq_max_pending[q]) {
+		ieee80211_wake_queue(sc->hw, q);
+		txq->stopped = false;
+	}
+}
+
 static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 {
 	struct ath_txq *txq = tid->ac->txq;
@@ -167,6 +189,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 		if (!bf) {
 			bf = ath_tx_setup_buffer(sc, txq, tid, skb);
 			if (!bf) {
+				ath_txq_skb_done(sc, txq, skb);
 				ieee80211_free_txskb(sc->hw, skb);
 				continue;
 			}
@@ -811,6 +834,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
 
 		if (!bf) {
 			__skb_unlink(skb, &tid->buf_q);
+			ath_txq_skb_done(sc, txq, skb);
 			ieee80211_free_txskb(sc->hw, skb);
 			continue;
 		}
@@ -1824,6 +1848,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq,
 
 	bf = ath_tx_setup_buffer(sc, txq, tid, skb);
 	if (!bf) {
+		ath_txq_skb_done(sc, txq, skb);
 		ieee80211_free_txskb(sc->hw, skb);
 		return;
 	}
@@ -2090,6 +2115,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 
 	bf = ath_tx_setup_buffer(sc, txq, tid, skb);
 	if (!bf) {
+		ath_txq_skb_done(sc, txq, skb);
 		if (txctl->paprd)
 			dev_kfree_skb_any(skb);
 		else
@@ -2189,7 +2215,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
-	int q, padpos, padsize;
+	int padpos, padsize;
 	unsigned long flags;
 
 	ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
@@ -2225,21 +2251,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
 	__skb_queue_tail(&txq->complete_q, skb);
-
-	q = skb_get_queue_mapping(skb);
-	if (txq == sc->tx.uapsdq)
-		txq = sc->tx.txq_map[q];
-
-	if (txq == sc->tx.txq_map[q]) {
-		if (WARN_ON(--txq->pending_frames < 0))
-			txq->pending_frames = 0;
-
-		if (txq->stopped &&
-		    txq->pending_frames < sc->tx.txq_max_pending[q]) {
-			ieee80211_wake_queue(sc->hw, q);
-			txq->stopped = false;
-		}
-	}
+	ath_txq_skb_done(sc, txq, skb);
 }
 
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
-- 
1.8.0.2


^ permalink raw reply related

* Re: [PATCH 00/19] rt2x00: add experimental support for RT3593
From: Andreas Hartmann @ 2013-06-30  8:59 UTC (permalink / raw)
  To: Gabor Juhos, John Linville; +Cc: linux-wireless, users
In-Reply-To: <1372446753-11408-1-git-send-email-juhosg@openwrt.org>

Hello Gabor,

bad guy is back again :-)

Gabor Juhos wrote:
> This patch-set implements experiemental support for the
> RT3593 chipset. The patches are tested on the Linksys
> AE3000 USB device only, however other USB devices which
> are using the RT3573 chips might work as well.

I did another test with raspberry pi. Same network parameters (2.4 GHz,
40MHz, eap-tls, ccmp/ccmp) but this time w/o any other load on the
wlan. But there is a reinforced-concrete floor between AP and STA.

netperf with rt2800usb / backports-20130617 / kernel 3.6.11 gives:

MIGRATED TCP STREAM TEST from 0.0.0.0 () port 0 AF_INET to server port 0 AF_INET
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.39      28.16   
MIGRATED TCP MAERTS TEST from 0.0.0.0 () port 0 AF_INET from server port 0 AF_INET
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.00      30.23   
TCP SENDFILE TEST from 0.0.0.0 () port 0 AF_INET to server port 0 AF_INET
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.35      27.69


Same with DPO_RT5572_LinuxSTA_2.6.1.3_20121022

MIGRATED TCP STREAM TEST from 0.0.0.0 () port 0 AF_INET to server port 0 AF_INET
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.01      97.95   
MIGRATED TCP MAERTS TEST from 0.0.0.0 () port 0 AF_INET from server port 0 AF_INET
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.01     121.69   
TCP SENDFILE TEST from 0.0.0.0 () port 0 AF_INET to server port 0 AF_INET
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.01      82.75

If you compare the result w/ rt2800usb/AE3000 with rt2800usb/rt3572[1]
you can see: no difference :-(.


Kind regards,
Andreas

[1] http://comments.gmane.org/gmane.linux.drivers.rt2x00.user/1992

^ permalink raw reply

* [WT PATCH 5/6] mac80211: Add debugfs for sdata and sdata->sta_vhash
From: greearb @ 2013-06-29 22:58 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1372546738-25827-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

This gives the user some idea how well the hash functions
are working.

Signed-off-by:  Ben Greear <greearb@candelatech.com>
---
 net/mac80211/debugfs.c        |   43 ++++++++++++++++++++++++++++++++
 net/mac80211/debugfs_netdev.c |   54 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 2bbe377..c18a6d1 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -210,9 +210,51 @@ static ssize_t sta_hash_read(struct file *file, char __user *user_buf,
 	return q;
 }
 
+static ssize_t sdata_hash_read(struct file *file, char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	struct ieee80211_local *local = file->private_data;
+	int mxln = 15000;
+	char *buf = kzalloc(mxln, GFP_KERNEL);
+	int q, res = 0;
+	struct ieee80211_sub_if_data *s;
+
+	if (!buf)
+		return 0;
+
+	mutex_lock(&local->iflist_mtx);
+	for (q = 0; q < STA_HASH_SIZE; q++) {
+		s = local->sdata_hash[q];
+		if (s) {
+			res += snprintf(buf + res, mxln - res, "%i: ", q);
+			if (res >= mxln)
+				goto done;
+		}
+		while (s) {
+			res += snprintf(buf + res, mxln - res, " %pM",
+					s->vif.addr);
+			if (res >= mxln)
+				goto done;
+			s = s->hnext;
+		}
+		if (local->sdata_hash[q]) {
+			res += snprintf(buf + res, mxln - res, "\n");
+			if (res >= mxln)
+				goto done;
+		}
+	}
+done:
+	mutex_unlock(&local->iflist_mtx);
+
+	q = simple_read_from_buffer(user_buf, count, ppos, buf, res);
+	kfree(buf);
+	return q;
+}
+
 DEBUGFS_READONLY_FILE_OPS(hwflags);
 DEBUGFS_READONLY_FILE_OPS(queues);
 DEBUGFS_READONLY_FILE_OPS(sta_hash);
+DEBUGFS_READONLY_FILE_OPS(sdata_hash);
 
 /* statistics stuff */
 
@@ -282,6 +324,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
 	DEBUGFS_ADD(wep_iv);
 	DEBUGFS_ADD(queues);
 	DEBUGFS_ADD(sta_hash);
+	DEBUGFS_ADD(sdata_hash);
 #ifdef CONFIG_PM
 	DEBUGFS_ADD_MODE(reset, 0200);
 #endif
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index cafe614..321460d 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -30,17 +30,22 @@ static ssize_t ieee80211_if_read(
 	size_t count, loff_t *ppos,
 	ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
 {
-	char buf[70];
+	int mxln = STA_HASH_SIZE * 10;
+	char *buf = kzalloc(mxln, GFP_KERNEL);
 	ssize_t ret = -EINVAL;
 
+	if (!buf)
+		return 0;
+
 	read_lock(&dev_base_lock);
 	if (sdata->dev->reg_state == NETREG_REGISTERED)
-		ret = (*format)(sdata, buf, sizeof(buf));
+		ret = (*format)(sdata, buf, mxln);
 	read_unlock(&dev_base_lock);
 
 	if (ret >= 0)
 		ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
 
+	kfree(buf);
 	return ret;
 }
 
@@ -201,6 +206,50 @@ ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata,
 }
 __IEEE80211_IF_FILE(hw_queues, NULL);
 
+static ssize_t
+ieee80211_if_fmt_sta_hash(const struct ieee80211_sub_if_data *sdata,
+			  char *buf, int buflen)
+{
+	int q, res = 0;
+	struct sta_info *sta;
+
+	mutex_lock(&sdata->local->sta_mtx);
+	for (q = 0; q < STA_HASH_SIZE; q++) {
+		int cnt = 0;
+		sta = sdata->sta_vhash[q];
+		while (sta) {
+			cnt++;
+			sta = sta->vnext;
+		}
+		if (cnt) {
+			res += snprintf(buf + res, buflen - res, "%i: %i ",
+					q, cnt);
+			if (res >= buflen) {
+				res = buflen;
+				break;
+			}
+			sta = sdata->sta_vhash[q];
+			while (sta) {
+				res += snprintf(buf + res, buflen - res, " %pM",
+						sta->sta.addr);
+				if (res >= buflen) {
+					res = buflen;
+					break;
+				}
+				sta = sta->vnext;
+			}
+			res += snprintf(buf + res, buflen - res, "\n");
+			if (res >= buflen) {
+				res = buflen;
+				break;
+			}
+		}
+	}
+	mutex_unlock(&sdata->local->sta_mtx);
+	return res;
+}
+__IEEE80211_IF_FILE(sta_hash, NULL);
+
 /* STA attributes */
 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
@@ -545,6 +594,7 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata)
 	DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
 	DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
 	DEBUGFS_ADD(hw_queues);
+	DEBUGFS_ADD(sta_hash);
 }
 
 static void add_sta_files(struct ieee80211_sub_if_data *sdata)
-- 
1.7.3.4


^ permalink raw reply related

* [WT PATCH 6/6] mac80211: Tell user why beacons fail to parse.
From: greearb @ 2013-06-29 22:58 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1372546738-25827-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

Should help better debug dodgy APs and such.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/mac80211/ieee80211_i.h |    2 +
 net/mac80211/mlme.c        |    4 +-
 net/mac80211/scan.c        |    6 +++
 net/mac80211/util.c        |   79 +++++++++++++++++++++++++++++++++++++++----
 4 files changed, 81 insertions(+), 10 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f36f120..809c9a5 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -110,6 +110,7 @@ struct ieee80211_bss {
 
 	/* Keep track of what bits of information we have valid info for. */
 	u8 valid_data;
+	char corrupt_elems_msg[80];
 };
 
 /**
@@ -1258,6 +1259,7 @@ struct ieee802_11_elems {
 
 	/* whether a parse error occurred while retrieving these elements */
 	bool parse_error;
+	char parse_err_msg[80];
 };
 
 static inline struct ieee80211_local *hw_to_local(
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ae31968..42edd6c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4341,8 +4341,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 				corrupt_type = "beacon";
 		} else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)
 			corrupt_type = "probe response";
-		sdata_info(sdata, "associating with AP with corrupt %s\n",
-			   corrupt_type);
+		sdata_info(sdata, "associating with AP with corrupt %s, reason: %s\n",
+			   corrupt_type, bss->corrupt_elems_msg);
 	}
 
 	return 0;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 1b122a7..9dc9c98 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -86,6 +86,8 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
 		bss->device_ts_presp = rx_status->device_timestamp;
 
 	if (elems->parse_error) {
+		strncpy(bss->corrupt_elems_msg, elems->parse_err_msg,
+			sizeof(bss->corrupt_elems_msg));
 		if (beacon)
 			bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON;
 		else
@@ -95,6 +97,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
 			bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_BEACON;
 		else
 			bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_PROBE_RESP;
+		if (!(bss->corrupt_data &
+		      (IEEE80211_BSS_CORRUPT_BEACON |
+		       IEEE80211_BSS_CORRUPT_PROBE_RESP)))
+			bss->corrupt_elems_msg[0] = 0;
 	}
 
 	/* save the ERP value so that it is available at association time */
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 2265445..7e6a4f3 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -692,6 +692,10 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 
 		if (elen > left) {
 			elems->parse_error = true;
+			snprintf(elems->parse_err_msg,
+				 sizeof(elems->parse_err_msg),
+				 "elen: %hhu > left: %zu",
+				 elen, left);
 			break;
 		}
 
@@ -731,6 +735,9 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 		 */
 			if (test_bit(id, seen_elems)) {
 				elems->parse_error = true;
+				snprintf(elems->parse_err_msg,
+					 sizeof(elems->parse_err_msg),
+					 "seen id: %i already", id);
 				left -= elen;
 				pos += elen;
 				continue;
@@ -762,8 +769,14 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 			if (elen >= sizeof(struct ieee80211_tim_ie)) {
 				elems->tim = (void *)pos;
 				elems->tim_len = elen;
-			} else
+			} else {
 				elem_parse_failed = true;
+				snprintf(elems->parse_err_msg,
+					 sizeof(elems->parse_err_msg),
+					 "EID_TIM size wrong, elen: %hhu  sizeof(tim_ie): %zu",
+					 elen,
+					 sizeof(struct ieee80211_tim_ie));
+			}
 			break;
 		case WLAN_EID_CHALLENGE:
 			elems->challenge = pos;
@@ -806,32 +819,61 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 		case WLAN_EID_HT_CAPABILITY:
 			if (elen >= sizeof(struct ieee80211_ht_cap))
 				elems->ht_cap_elem = (void *)pos;
-			else
+			else {
 				elem_parse_failed = true;
+				snprintf(elems->parse_err_msg,
+					 sizeof(elems->parse_err_msg),
+					 "HT_CAPAB size wrong, elen: %hhu  sizeof(ht_cap): %zu",
+					 elen,
+					 sizeof(struct ieee80211_ht_cap));
+			}
 			break;
 		case WLAN_EID_HT_OPERATION:
 			if (elen >= sizeof(struct ieee80211_ht_operation))
 				elems->ht_operation = (void *)pos;
-			else
+			else {
 				elem_parse_failed = true;
+				snprintf(elems->parse_err_msg,
+					 sizeof(elems->parse_err_msg),
+					 "HT_OPER size wrong, elen: %hhu  sizeof(ht_oper): %zu",
+					 elen,
+					 sizeof(struct ieee80211_ht_operation));
+			}
 			break;
 		case WLAN_EID_VHT_CAPABILITY:
 			if (elen >= sizeof(struct ieee80211_vht_cap))
 				elems->vht_cap_elem = (void *)pos;
-			else
+			else {
 				elem_parse_failed = true;
+				snprintf(elems->parse_err_msg,
+					 sizeof(elems->parse_err_msg),
+					 "EID_VHT size wrong, elen: %hhu  sizeof(vht_cap): %zu",
+					 elen,
+					 sizeof(struct ieee80211_vht_cap));
+			}
 			break;
 		case WLAN_EID_VHT_OPERATION:
 			if (elen >= sizeof(struct ieee80211_vht_operation))
 				elems->vht_operation = (void *)pos;
-			else
+			else {
 				elem_parse_failed = true;
+				snprintf(elems->parse_err_msg,
+					 sizeof(elems->parse_err_msg),
+					 "VHT_OPER size wrong, elen: %hhu  sizeof(vht_oper): %zu",
+					 elen,
+					 sizeof(struct ieee80211_vht_operation));
+			}
 			break;
 		case WLAN_EID_OPMODE_NOTIF:
 			if (elen > 0)
 				elems->opmode_notif = pos;
-			else
+			else {
 				elem_parse_failed = true;
+				snprintf(elems->parse_err_msg,
+					 sizeof(elems->parse_err_msg),
+					 "OPMODE_NOTIF has elen > 0: %hhu",
+					 elen);
+			}
 			break;
 		case WLAN_EID_MESH_ID:
 			elems->mesh_id = pos;
@@ -840,8 +882,14 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 		case WLAN_EID_MESH_CONFIG:
 			if (elen >= sizeof(struct ieee80211_meshconf_ie))
 				elems->mesh_config = (void *)pos;
-			else
+			else {
 				elem_parse_failed = true;
+				snprintf(elems->parse_err_msg,
+					 sizeof(elems->parse_err_msg),
+					 "MESH_CONFIG size wrong, elen: %hhu  sizeof(meshconf_ie): %zu",
+					 elen,
+					 sizeof(struct ieee80211_meshconf_ie));
+			}
 			break;
 		case WLAN_EID_PEER_MGMT:
 			elems->peering = pos;
@@ -866,12 +914,23 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 		case WLAN_EID_RANN:
 			if (elen >= sizeof(struct ieee80211_rann_ie))
 				elems->rann = (void *)pos;
-			else
+			else {
 				elem_parse_failed = true;
+				snprintf(elems->parse_err_msg,
+					 sizeof(elems->parse_err_msg),
+					 "EID_RANN size wrong, elen: %hhu  sizeof(rann_ie): %zu",
+					 elen,
+					 sizeof(struct ieee80211_rann_ie));
+			}
 			break;
 		case WLAN_EID_CHANNEL_SWITCH:
 			if (elen != sizeof(struct ieee80211_channel_sw_ie)) {
 				elem_parse_failed = true;
+				snprintf(elems->parse_err_msg,
+					 sizeof(elems->parse_err_msg),
+					 "CH_SWITCH size wrong, elen: %hhu  sizeof(sw_ie): %zu",
+					 elen,
+					 sizeof(struct ieee80211_channel_sw_ie));
 				break;
 			}
 			elems->ch_switch_ie = (void *)pos;
@@ -925,6 +984,10 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 		case WLAN_EID_PWR_CONSTRAINT:
 			if (elen != 1) {
 				elem_parse_failed = true;
+				snprintf(elems->parse_err_msg,
+					 sizeof(elems->parse_err_msg),
+					 "PWR_CONSTRAINT size not 1, elen: %hhu",
+					 elen);
 				break;
 			}
 			elems->pwr_constr_elem = pos;
-- 
1.7.3.4


^ permalink raw reply related

* [WT PATCH 4/6] mac80211: Add per-sdata station hash, and sdata hash.
From: greearb @ 2013-06-29 22:58 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1372546738-25827-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

Add sdata hash (based on sdata->vif.addr) to local
structure.

Add sta_vhash (based on sta->sta.addr) to sdata struct.

Make STA_HASH give a better hash spread more often.

Use new hashes where we can.  Might be able to completely
get rid of the local->sta_hash, but didn't want to try that
quite yet.

This significantly improves performance when using lots
of station VIFs connected to the same AP.  It will likely
help other cases where the old hash logic failed to create
a decent spread.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/mac80211/ieee80211_i.h |   34 +++++++++++++++
 net/mac80211/iface.c       |   50 ++++++++++++++++++++++-
 net/mac80211/rx.c          |   16 +++++++
 net/mac80211/sta_info.c    |   97 +++++++++++++++++++++++++++++++++++---------
 net/mac80211/sta_info.h    |   18 +++++++-
 net/mac80211/status.c      |    6 +++
 6 files changed, 198 insertions(+), 23 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8412a30..f36f120 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -670,6 +670,10 @@ struct ieee80211_chanctx {
 
 struct ieee80211_sub_if_data {
 	struct list_head list;
+	struct ieee80211_sub_if_data *hnext; /* sdata hash list pointer */
+
+	/* Protected by local->sta_mtx */
+	struct sta_info __rcu *sta_vhash[STA_HASH_SIZE]; /* By station addr */
 
 	struct wireless_dev wdev;
 
@@ -794,6 +798,34 @@ sdata_assert_lock(struct ieee80211_sub_if_data *sdata)
 	lockdep_assert_held(&sdata->wdev.mtx);
 }
 
+static inline
+void for_each_sdata_type_check(struct ieee80211_local *local,
+			       const u8 *addr,
+			       struct ieee80211_sub_if_data *sdata,
+			       struct ieee80211_sub_if_data *nxt)
+{
+}
+
+/* This deals with multiple sdata having same MAC */
+#define for_each_sdata(local, _addr, _sdata, nxt)			\
+	for (   /* initialise loop */					\
+		_sdata = rcu_dereference(local->sdata_hash[STA_HASH(_addr)]), \
+			nxt = _sdata ? rcu_dereference(_sdata->hnext) : NULL; \
+		/* typecheck */						\
+		for_each_sdata_type_check(local, (_addr), _sdata, nxt), \
+			/* continue condition */			\
+			_sdata;						\
+		/* advance loop */					\
+		_sdata = nxt,						\
+			nxt = _sdata ? rcu_dereference(_sdata->hnext) : NULL \
+		)							\
+		/* compare address and run code only if it matches */	\
+		if (ether_addr_equal(_sdata->vif.addr, (_addr)))
+
+
+struct ieee80211_sub_if_data*
+ieee80211_find_sdata(struct ieee80211_local *local, const u8 *vif_addr);
+
 static inline enum ieee80211_band
 ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata)
 {
@@ -1009,6 +1041,8 @@ struct ieee80211_local {
 	u32 wep_iv;
 
 	/* see iface.c */
+	/* Hash interfaces by VIF mac addr */
+	struct ieee80211_sub_if_data __rcu *sdata_hash[STA_HASH_SIZE];
 	struct list_head interfaces;
 	struct mutex iflist_mtx;
 
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index a2a8250..1bf7996 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -208,6 +208,47 @@ static int ieee80211_verify_mac(struct ieee80211_sub_if_data *sdata, u8 *addr,
 	return ret;
 }
 
+
+static void __ieee80211_if_add_hash(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	int idx = STA_HASH(sdata->vif.addr);
+
+	lockdep_assert_held(&local->iflist_mtx);
+	sdata->hnext = local->sdata_hash[idx];
+	rcu_assign_pointer(local->sdata_hash[idx], sdata);
+}
+
+static int __ieee80211_if_remove_hash(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_sub_if_data *s;
+	struct ieee80211_local *local = sdata->local;
+	int idx = STA_HASH(sdata->vif.addr);
+
+	lockdep_assert_held(&local->iflist_mtx);
+	s = rcu_dereference_protected(local->sdata_hash[idx],
+				      lockdep_is_held(&local->iflist_mtx));
+	if (!s)
+		return -ENOENT;
+
+	if (s == sdata) {
+		rcu_assign_pointer(local->sdata_hash[idx], s->hnext);
+		return 0;
+	}
+
+	while (rcu_access_pointer(s->hnext) &&
+	       rcu_access_pointer(s->hnext) != sdata)
+		s = rcu_dereference_protected(s->hnext,
+					lockdep_is_held(&local->iflist_mtx));
+
+	if (rcu_access_pointer(s->hnext)) {
+		rcu_assign_pointer(s->hnext, sdata->hnext);
+		return 0;
+	}
+	return -ENOENT;
+}
+
+
 static int ieee80211_change_mac(struct net_device *dev, void *addr)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -228,8 +269,13 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
 
 	ret = eth_mac_addr(dev, sa);
 
-	if (ret == 0)
+	if (ret == 0) {
+		mutex_lock(&sdata->local->iflist_mtx);
+		__ieee80211_if_remove_hash(sdata);
 		memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
+		__ieee80211_if_add_hash(sdata);
+		mutex_unlock(&sdata->local->iflist_mtx);
+	}
 
 	return ret;
 }
@@ -1688,6 +1734,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
 	mutex_lock(&local->iflist_mtx);
 	list_add_tail_rcu(&sdata->list, &local->interfaces);
+	__ieee80211_if_add_hash(sdata);
 	mutex_unlock(&local->iflist_mtx);
 
 	if (new_wdev)
@@ -1702,6 +1749,7 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
 
 	mutex_lock(&sdata->local->iflist_mtx);
 	list_del_rcu(&sdata->list);
+	__ieee80211_if_remove_hash(sdata);
 	mutex_unlock(&sdata->local->iflist_mtx);
 
 	synchronize_rcu();
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 23dbcfc..67efa59 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3172,6 +3172,21 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 	if (ieee80211_is_data(fc)) {
 		prev_sta = NULL;
 
+		/* Check for Station VIFS by hashing on the destination MAC
+		 * (ie, local sdata MAC).  This changes 'promisc' behaviour,
+		 * but not sure that is a bad thing.
+		 */
+		if ((!is_multicast_ether_addr(hdr->addr1)) &&
+		    (local->monitors == 0) && (local->cooked_mntrs == 0)) {
+			sta = sta_info_get_by_vif(local, hdr->addr1,
+						  hdr->addr2);
+			if (sta) {
+				rx.sta = sta;
+				rx.sdata = sta->sdata;
+				goto rx_and_done;
+			}
+		}
+
 		for_each_sta_info(local, hdr->addr2, sta, tmp) {
 			if (!prev_sta) {
 				prev_sta = sta;
@@ -3189,6 +3204,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 			rx.sta = prev_sta;
 			rx.sdata = prev_sta->sdata;
 
+rx_and_done:
 			if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
 				return;
 			goto out;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index aeb967a..44bb89b 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -68,27 +68,54 @@ static int sta_info_hash_del(struct ieee80211_local *local,
 			     struct sta_info *sta)
 {
 	struct sta_info *s;
+	int rv = -ENOENT;
+	int idx = STA_HASH(sta->sta.addr);
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
 
-	s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)],
+	s = rcu_dereference_protected(local->sta_hash[idx],
 				      lockdep_is_held(&local->sta_mtx));
 	if (!s)
-		return -ENOENT;
+		/* If station is not in the main hash, then it definitely
+		 * should not be in the vhash, so we can just return.
+		 */
+		return rv;
+
 	if (s == sta) {
-		rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)],
-				   s->hnext);
-		return 0;
+		rcu_assign_pointer(local->sta_hash[idx], s->hnext);
+		rv = 0;
+		goto try_vhash;
 	}
 
 	while (rcu_access_pointer(s->hnext) &&
 	       rcu_access_pointer(s->hnext) != sta)
 		s = rcu_dereference_protected(s->hnext,
-					lockdep_is_held(&local->sta_mtx));
+					      lockdep_is_held(&local->sta_mtx));
 	if (rcu_access_pointer(s->hnext)) {
 		rcu_assign_pointer(s->hnext, sta->hnext);
-		return 0;
+		rv = 0;
+		goto try_vhash;
 	}
+	return rv;
 
-	return -ENOENT;
+try_vhash:
+	s = rcu_dereference_protected(sdata->sta_vhash[idx],
+				      lockdep_is_held(&local->sta_mtx));
+	if (!s)
+		return rv;
+
+	if (s == sta) {
+		rcu_assign_pointer(sdata->sta_vhash[idx], s->vnext);
+		return rv;
+	}
+
+	while (rcu_access_pointer(s->vnext) &&
+	       rcu_access_pointer(s->vnext) != sta)
+		s = rcu_dereference_protected(s->vnext,
+					      lockdep_is_held(&local->sta_mtx));
+	if (rcu_access_pointer(s->vnext))
+		rcu_assign_pointer(s->vnext, sta->vnext);
+
+	return rv;
 }
 
 static void cleanup_single_sta(struct sta_info *sta)
@@ -195,17 +222,15 @@ static void free_sta_rcu(struct rcu_head *h)
 struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
 			      const u8 *addr)
 {
-	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 
-	sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
-				    lockdep_is_held(&local->sta_mtx));
+	sta = rcu_dereference_check(sdata->sta_vhash[STA_HASH(addr)],
+				    lockdep_is_held(&sdata->local->sta_mtx));
 	while (sta) {
-		if (sta->sdata == sdata &&
-		    ether_addr_equal(sta->sta.addr, addr))
+		if (ether_addr_equal(sta->sta.addr, addr))
 			break;
-		sta = rcu_dereference_check(sta->hnext,
-					    lockdep_is_held(&local->sta_mtx));
+		sta = rcu_dereference_check(sta->vnext,
+				lockdep_is_held(&sdata->local->sta_mtx));
 	}
 	return sta;
 }
@@ -220,6 +245,13 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 
+	sta = sta_info_get(sdata, addr);
+	if (sta)
+		return sta;
+
+	/* Maybe it's on some other sdata matching the bss, try
+	 * a bit harder.
+	 */
 	sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
 				    lockdep_is_held(&local->sta_mtx));
 	while (sta) {
@@ -233,6 +265,22 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
 	return sta;
 }
 
+struct sta_info *sta_info_get_by_vif(struct ieee80211_local *local,
+				     const u8 *vif_addr, const u8 *sta_addr)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_sub_if_data *nxt;
+	struct sta_info *sta;
+
+	for_each_sdata(local, vif_addr, sdata, nxt) {
+		sta = sta_info_get(sdata, sta_addr);
+		if (sta)
+			return sta;
+	}
+	return NULL;
+}
+
+
 struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
 				     int idx)
 {
@@ -278,9 +326,14 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
 static void sta_info_hash_add(struct ieee80211_local *local,
 			      struct sta_info *sta)
 {
+	int idx = STA_HASH(sta->sta.addr);
+
 	lockdep_assert_held(&local->sta_mtx);
-	sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)];
-	rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
+	sta->hnext = local->sta_hash[idx];
+	rcu_assign_pointer(local->sta_hash[idx], sta);
+
+	sta->vnext = sta->sdata->sta_vhash[idx];
+	rcu_assign_pointer(sta->sdata->sta_vhash[idx], sta);
 }
 
 static void sta_unblock(struct work_struct *wk)
@@ -975,14 +1028,18 @@ struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,
 {
 	struct sta_info *sta, *nxt;
 
+	if (localaddr) {
+		sta = sta_info_get_by_vif(hw_to_local(hw), localaddr, addr);
+		if (sta && sta->uploaded)
+			return &sta->sta;
+		return NULL;
+	}
+
 	/*
 	 * Just return a random station if localaddr is NULL
 	 * ... first in list.
 	 */
 	for_each_sta_info(hw_to_local(hw), addr, sta, nxt) {
-		if (localaddr &&
-		    !ether_addr_equal(sta->sdata->vif.addr, localaddr))
-			continue;
 		if (!sta->uploaded)
 			return NULL;
 		return &sta->sta;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 4208dbd..963de5e 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -15,6 +15,7 @@
 #include <linux/workqueue.h>
 #include <linux/average.h>
 #include <linux/etherdevice.h>
+#include <linux/hash.h>
 #include "key.h"
 
 /**
@@ -228,7 +229,8 @@ struct sta_ampdu_mlme {
  * mac80211 is communicating with.
  *
  * @list: global linked list entry
- * @hnext: hash table linked list pointer
+ * @hnext: hash table linked list pointer, used by local->sta_hash
+ * @vnext: hash table linked list pointer, used by sdata->sta_vhash.
  * @local: pointer to the global information
  * @sdata: virtual interface this station belongs to
  * @ptk: peer key negotiated with this station, if any
@@ -307,6 +309,7 @@ struct sta_info {
 	struct list_head list;
 	struct rcu_head rcu_head;
 	struct sta_info __rcu *hnext;
+	struct sta_info __rcu *vnext;
 	struct ieee80211_local *local;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
@@ -492,7 +495,12 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid)
 }
 
 #define STA_HASH_SIZE 256
-#define STA_HASH(sta) (sta[5])
+static inline u32 STA_HASH(const unsigned char *addr)
+{
+	u32 v = (addr[0] << 8) | addr[1];
+	v ^= (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
+	return hash_32(v, 8);
+}
 
 
 /* Maximum number of frames to buffer per power saving station per AC */
@@ -514,6 +522,12 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
 
 struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
 				  const u8 *addr);
+/*
+ * Uses the local->sdata hash and sdata->sta_hash for fast lookup
+ * base on VIF (sdata) address and remote station address.
+ */
+struct sta_info *sta_info_get_by_vif(struct ieee80211_local *local,
+				     const u8 *vif_addr, const u8 *sta_addr);
 
 static inline
 void for_each_sta_info_type_check(struct ieee80211_local *local,
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 4343920..0ecab1a 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -453,11 +453,16 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 	sband = local->hw.wiphy->bands[info->band];
 	fc = hdr->frame_control;
 
+	sta = sta_info_get_by_vif(local, hdr->addr2, hdr->addr1);
+	if (sta)
+		goto found_it;
+
 	for_each_sta_info(local, hdr->addr1, sta, tmp) {
 		/* skip wrong virtual interface */
 		if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
 			continue;
 
+found_it:
 		if (info->flags & IEEE80211_TX_STATUS_EOSP)
 			clear_sta_flag(sta, WLAN_STA_SP);
 
@@ -553,6 +558,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 		if (acked)
 			sta->last_ack_signal = info->status.ack_signal;
+		break;
 	}
 
 	rcu_read_unlock();
-- 
1.7.3.4


^ permalink raw reply related

* [WT PATCH 3/6] wireless: Add memory usage debugging.
From: greearb @ 2013-06-29 22:58 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1372546738-25827-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

The bss objects are reference counted, and the ies
are also tricky to keep track of.  Add module option to
track allocation and freeing of the ies and bss objects,
and add debugfs files to show the current objects.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/wireless/core.c    |    9 +++-
 net/wireless/core.h    |   16 ++++++
 net/wireless/debugfs.c |  113 +++++++++++++++++++++++++++++++++++++++
 net/wireless/debugfs.h |    2 +
 net/wireless/scan.c    |  139 ++++++++++++++++++++++++++++++++++++++++++-----
 5 files changed, 262 insertions(+), 17 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 672459b..861fc37 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -50,6 +50,10 @@ static bool cfg80211_disable_40mhz_24ghz;
 module_param(cfg80211_disable_40mhz_24ghz, bool, 0644);
 MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz,
 		 "Disable 40MHz support in the 2.4GHz band");
+bool cfg80211_mem_debugging;
+module_param(cfg80211_mem_debugging, bool, 0644);
+MODULE_PARM_DESC(cfg80211_mem_debugging,
+		 "Enable memory tracking for ies and bss objects.");
 
 struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
 {
@@ -996,6 +1000,7 @@ static int __init cfg80211_init(void)
 		goto out_fail_nl80211;
 
 	ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
+	ieee80211_debugfs_add_glbl(ieee80211_debugfs_dir);
 
 	err = regulatory_init();
 	if (err)
@@ -1012,7 +1017,7 @@ static int __init cfg80211_init(void)
 out_fail_wq:
 	regulatory_exit();
 out_fail_reg:
-	debugfs_remove(ieee80211_debugfs_dir);
+	debugfs_remove_recursive(ieee80211_debugfs_dir);
 out_fail_nl80211:
 	unregister_netdevice_notifier(&cfg80211_netdev_notifier);
 out_fail_notifier:
@@ -1026,7 +1031,7 @@ subsys_initcall(cfg80211_init);
 
 static void __exit cfg80211_exit(void)
 {
-	debugfs_remove(ieee80211_debugfs_dir);
+	debugfs_remove_recursive(ieee80211_debugfs_dir);
 	nl80211_exit();
 	unregister_netdevice_notifier(&cfg80211_netdev_notifier);
 	wiphy_sysfs_exit();
diff --git a/net/wireless/core.h b/net/wireless/core.h
index a6b45bf..74d694f 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -114,6 +114,22 @@ extern struct workqueue_struct *cfg80211_wq;
 extern struct list_head cfg80211_rdev_list;
 extern int cfg80211_rdev_list_generation;
 
+extern bool cfg80211_mem_debugging; /* module option */
+#ifdef CONFIG_CFG80211_DEBUGFS
+struct wifi_mem_tracker {
+	struct list_head mylist;
+	char buf[40];
+	void *ptr;
+};
+extern struct list_head ies_list;
+extern spinlock_t ies_lock;
+extern atomic_t ies_count;
+
+extern struct list_head bss_list;
+extern spinlock_t bss_lock;
+extern atomic_t bss_count;
+#endif
+
 struct cfg80211_internal_bss {
 	struct list_head list;
 	struct list_head hidden_list;
diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c
index 90d0500..fd52bb1 100644
--- a/net/wireless/debugfs.c
+++ b/net/wireless/debugfs.c
@@ -31,6 +31,108 @@ static const struct file_operations name## _ops = {			\
 	.llseek = generic_file_llseek,					\
 };
 
+#define DEBUGFS_READONLY_FILE_OPS(name) \
+static const struct file_operations name## _ops = {			\
+	.read = name## _read,						\
+	.open = simple_open,						\
+	.llseek = generic_file_llseek,					\
+};
+
+static ssize_t all_ies_read(struct file *file, char __user *user_buf,
+				size_t count, loff_t *ppos)
+{
+	int mxln = 31500;
+	char *buf = kzalloc(mxln, GFP_KERNEL);
+	int q, res = 0;
+	struct wifi_mem_tracker *iesm;
+
+	if (!buf)
+		return 0;
+
+	spin_lock_bh(&ies_lock);
+	res += sprintf(buf + res, "Total: %i\n", atomic_read(&ies_count));
+	list_for_each_entry(iesm, &ies_list, mylist) {
+		res += sprintf(buf + res, "%p: %s\n",
+			       iesm->ptr, iesm->buf);
+		if (res >= mxln) {
+			res = mxln;
+			break;
+		}
+	}
+	spin_unlock_bh(&ies_lock);
+
+	q = simple_read_from_buffer(user_buf, count, ppos, buf, res);
+	kfree(buf);
+	return q;
+}
+
+static ssize_t all_bss_read(struct file *file, char __user *user_buf,
+			    size_t count, loff_t *ppos)
+{
+	int mxln = 31500;
+	char *buf = kzalloc(mxln, GFP_KERNEL);
+	int q, res = 0;
+	struct wifi_mem_tracker *bssm;
+
+	if (!buf)
+		return 0;
+
+	spin_lock_bh(&bss_lock);
+	res += sprintf(buf + res, "Total: %i\n", atomic_read(&bss_count));
+	list_for_each_entry(bssm, &bss_list, mylist) {
+		struct cfg80211_internal_bss *bss;
+		bss = (struct cfg80211_internal_bss *)(bssm->ptr);
+		res += sprintf(buf + res, "%p: #%lu %s\n",
+			       bssm->ptr, bss->refcount, bssm->buf);
+		if (res >= mxln) {
+			res = mxln;
+			break;
+		}
+	}
+	spin_unlock_bh(&bss_lock);
+
+	q = simple_read_from_buffer(user_buf, count, ppos, buf, res);
+	kfree(buf);
+	return q;
+}
+
+DEBUGFS_READONLY_FILE_OPS(all_ies);
+DEBUGFS_READONLY_FILE_OPS(all_bss);
+
+
+static ssize_t bss_read(struct file *file, char __user *user_buf,
+			size_t count, loff_t *ppos)
+{
+	struct wiphy *wiphy = file->private_data;
+	struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+	int mxln = 31500;
+	char *buf = kzalloc(mxln, GFP_KERNEL);
+	int q, res = 0;
+	struct cfg80211_internal_bss *bss;
+
+	if (!buf)
+		return 0;
+
+	spin_lock_bh(&dev->bss_lock);
+	list_for_each_entry(bss, &dev->bss_list, list) {
+		res += sprintf(buf + res,
+			       "%p: #%lu  bcn: %p  pr: %p  hidden: %p\n",
+			       bss, bss->refcount,
+			       rcu_access_pointer(bss->pub.beacon_ies),
+			       rcu_access_pointer(bss->pub.proberesp_ies),
+			       bss->pub.hidden_beacon_bss);
+		if (res >= mxln) {
+			res = mxln;
+			break;
+		}
+	}
+	spin_unlock_bh(&dev->bss_lock);
+
+	q = simple_read_from_buffer(user_buf, count, ppos, buf, res);
+	kfree(buf);
+	return q;
+}
+
 DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
 		      wiphy->rts_threshold)
 DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
@@ -39,6 +141,7 @@ DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
 		      wiphy->retry_short)
 DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
 		      wiphy->retry_long);
+DEBUGFS_READONLY_FILE_OPS(bss);
 
 static int ht_print_chan(struct ieee80211_channel *chan,
 			 char *buf, int buf_size, int offset)
@@ -112,4 +215,14 @@ void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev)
 	DEBUGFS_ADD(short_retry_limit);
 	DEBUGFS_ADD(long_retry_limit);
 	DEBUGFS_ADD(ht40allow_map);
+	DEBUGFS_ADD(bss);
+}
+
+#define DEBUGFS_ADD_GLBL(name)						\
+	debugfs_create_file(#name, S_IRUGO, dir, NULL, &name## _ops);
+
+void ieee80211_debugfs_add_glbl(struct dentry *dir)
+{
+	DEBUGFS_ADD_GLBL(all_ies);
+	DEBUGFS_ADD_GLBL(all_bss);
 }
diff --git a/net/wireless/debugfs.h b/net/wireless/debugfs.h
index 74fdd38..f644869 100644
--- a/net/wireless/debugfs.h
+++ b/net/wireless/debugfs.h
@@ -3,9 +3,11 @@
 
 #ifdef CONFIG_CFG80211_DEBUGFS
 void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev);
+void ieee80211_debugfs_add_glbl(struct dentry *dir);
 #else
 static inline
 void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) {}
+static inline void ieee80211_debugfs_add_glbl(struct dentry *dir) { }
 #endif
 
 #endif /* __CFG80211_DEBUGFS_H */
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index ae8c186..2d66334 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -57,6 +57,118 @@
 
 #define IEEE80211_SCAN_RESULT_EXPIRE	(30 * HZ)
 
+#ifdef CONFIG_CFG80211_DEBUGFS
+/* memory debugging structures, only useful when debugfs
+ * is enabled.
+ */
+LIST_HEAD(ies_list);
+DEFINE_SPINLOCK(ies_lock);
+atomic_t ies_count = ATOMIC_INIT(0);
+
+LIST_HEAD(bss_list);
+DEFINE_SPINLOCK(bss_lock);
+atomic_t bss_count = ATOMIC_INIT(0);
+
+
+static void my_kfree_rcu_ies(struct cfg80211_bss_ies *ies)
+{
+	if (cfg80211_mem_debugging) {
+		struct wifi_mem_tracker *iesm;
+		spin_lock_bh(&ies_lock);
+		list_for_each_entry(iesm, &ies_list, mylist) {
+			if (iesm->ptr == ies) {
+				list_del(&iesm->mylist);
+				kfree(iesm);
+				break;
+			}
+		}
+		spin_unlock_bh(&ies_lock);
+	}
+	atomic_sub(1, &ies_count);
+	kfree_rcu(ies, rcu_head);
+}
+
+#define my_kmalloc_ies(s, g)				\
+	_my_kmalloc_ies(s, g, __LINE__);
+
+static void* _my_kmalloc_ies(size_t s, gfp_t gfp, int l)
+{
+	void *rv = kmalloc(s, gfp);
+	if (rv) {
+		atomic_add(1, &ies_count);
+		if (cfg80211_mem_debugging) {
+			struct wifi_mem_tracker *iesm;
+			iesm = kmalloc(sizeof(*iesm), gfp);
+			if (iesm) {
+				snprintf(iesm->buf, sizeof(iesm->buf), "%i", l);
+				iesm->buf[sizeof(iesm->buf)-1] = 0;
+				iesm->ptr = rv;
+				INIT_LIST_HEAD(&iesm->mylist);
+				spin_lock_bh(&ies_lock);
+				list_add(&iesm->mylist, &ies_list);
+				spin_unlock_bh(&ies_lock);
+			} else {
+				pr_err("ERROR:  Could not allocate iesm.\n");
+			}
+		}
+	}
+	return rv;
+}
+
+static void my_kfree_bss(struct cfg80211_internal_bss *bss)
+{
+	if (cfg80211_mem_debugging) {
+		struct wifi_mem_tracker *bssm;
+		spin_lock_bh(&bss_lock);
+		list_for_each_entry(bssm, &bss_list, mylist) {
+			if (bssm->ptr == bss) {
+				list_del(&bssm->mylist);
+				kfree(bssm);
+				break;
+			}
+		}
+		spin_unlock_bh(&bss_lock);
+	}
+	atomic_sub(1, &bss_count);
+	kfree(bss);
+}
+
+#define my_kzalloc_bss(s, g)				\
+	_my_kzalloc_bss(s, g, __LINE__);
+
+static void* _my_kzalloc_bss(size_t s, gfp_t gfp, int l)
+{
+	void *rv = kmalloc(s, gfp);
+	if (rv) {
+		atomic_add(1, &bss_count);
+		if (cfg80211_mem_debugging) {
+			struct wifi_mem_tracker *bssm;
+			bssm = kmalloc(sizeof(*bssm), gfp);
+			if (bssm) {
+				snprintf(bssm->buf, sizeof(bssm->buf), "%i", l);
+				bssm->buf[sizeof(bssm->buf)-1] = 0;
+				bssm->ptr = rv;
+				INIT_LIST_HEAD(&bssm->mylist);
+				spin_lock_bh(&bss_lock);
+				list_add(&bssm->mylist, &bss_list);
+				spin_unlock_bh(&bss_lock);
+			} else {
+				pr_err("ERROR:  Could not allocate bssm for bss.\n");
+			}
+		}
+	}
+	return rv;
+}
+
+#else
+
+#define my_kfree_rcu_ies(ies) kfree_rcu(ies, rcu_head)
+#define my_kmalloc_ies(s, g) kmalloc(s, g)
+#define my_kfree_bss(a) kfree(a)
+#define my_kzalloc_bss(s, g) kzalloc(s, g)
+
+#endif
+
 static void bss_free(struct cfg80211_internal_bss *bss)
 {
 	struct cfg80211_bss_ies *ies;
@@ -66,10 +178,10 @@ static void bss_free(struct cfg80211_internal_bss *bss)
 
 	ies = (void *)rcu_access_pointer(bss->pub.beacon_ies);
 	if (ies && !bss->pub.hidden_beacon_bss)
-		kfree_rcu(ies, rcu_head);
+		my_kfree_rcu_ies(ies);
 	ies = (void *)rcu_access_pointer(bss->pub.proberesp_ies);
 	if (ies)
-		kfree_rcu(ies, rcu_head);
+		my_kfree_rcu_ies(ies);
 
 	/*
 	 * This happens when the module is removed, it doesn't
@@ -78,7 +190,7 @@ static void bss_free(struct cfg80211_internal_bss *bss)
 	if (!list_empty(&bss->hidden_list))
 		list_del(&bss->hidden_list);
 
-	kfree(bss);
+	my_kfree_bss(bss);
 }
 
 static inline void bss_ref_get(struct cfg80211_registered_device *dev,
@@ -713,8 +825,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 			rcu_assign_pointer(found->pub.ies,
 					   tmp->pub.proberesp_ies);
 			if (old)
-				kfree_rcu((struct cfg80211_bss_ies *)old,
-					  rcu_head);
+				my_kfree_rcu_ies((struct cfg80211_bss_ies *)old);
 		} else if (rcu_access_pointer(tmp->pub.beacon_ies)) {
 			const struct cfg80211_bss_ies *old;
 			struct cfg80211_internal_bss *bss;
@@ -734,8 +845,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 				 */
 
 				f = rcu_access_pointer(tmp->pub.beacon_ies);
-				kfree_rcu((struct cfg80211_bss_ies *)f,
-					  rcu_head);
+				my_kfree_rcu_ies((struct cfg80211_bss_ies *)f);
 				goto drop;
 			}
 
@@ -762,8 +872,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 			}
 
 			if (old)
-				kfree_rcu((struct cfg80211_bss_ies *)old,
-					  rcu_head);
+				my_kfree_rcu_ies((struct cfg80211_bss_ies *)old);
 		}
 
 		found->pub.beacon_interval = tmp->pub.beacon_interval;
@@ -780,15 +889,15 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 		 * is allocated on the stack since it's not needed in the
 		 * more common case of an update
 		 */
-		new = kzalloc(sizeof(*new) + dev->wiphy.bss_priv_size,
-			      GFP_ATOMIC);
+		new = my_kzalloc_bss(sizeof(*new) + dev->wiphy.bss_priv_size,
+				     GFP_ATOMIC);
 		if (!new) {
 			ies = (void *)rcu_dereference(tmp->pub.beacon_ies);
 			if (ies)
-				kfree_rcu(ies, rcu_head);
+				my_kfree_rcu_ies(ies);
 			ies = (void *)rcu_dereference(tmp->pub.proberesp_ies);
 			if (ies)
-				kfree_rcu(ies, rcu_head);
+				my_kfree_rcu_ies(ies);
 			goto drop;
 		}
 		memcpy(new, tmp, sizeof(*new));
@@ -903,7 +1012,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
 	 * override the IEs pointer should we have received an earlier
 	 * indication of Probe Response data.
 	 */
-	ies = kmalloc(sizeof(*ies) + ielen, gfp);
+	ies = my_kmalloc_ies(sizeof(*ies) + ielen, gfp);
 	if (!ies)
 		return NULL;
 	ies->len = ielen;
@@ -961,7 +1070,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
 	if (!channel)
 		return NULL;
 
-	ies = kmalloc(sizeof(*ies) + ielen, gfp);
+	ies = my_kmalloc_ies(sizeof(*ies) + ielen, gfp);
 	if (!ies)
 		return NULL;
 	ies->len = ielen;
-- 
1.7.3.4


^ permalink raw reply related

* [WT PATCH 2/6] mac80211: Make un-found-rate splat a warn-once.
From: greearb @ 2013-06-29 22:58 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1372546738-25827-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

After that, print it out with net_ratelimit.  We saw a system
continually hit this warning, for reasons unknown, and it
seems it bogged the system down enough to make it go OOM.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/mac80211/tx.c |   21 ++++++++++++++-------
 1 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4105d0c..8601f3f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -678,14 +678,21 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 	 * Lets not bother rate control if we're associated and cannot
 	 * talk to the sta. This should not happen.
 	 */
-	if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
-		 !rate_usable_index_exists(sband, &tx->sta->sta),
-		 "%s: Dropped data frame as no usable bitrate found while "
-		 "scanning and associated. Target station: "
-		 "%pM on %d GHz band\n",
-		 tx->sdata->name, hdr->addr1,
-		 info->band ? 5 : 2))
+	if (test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
+	    !rate_usable_index_exists(sband, &tx->sta->sta)) {
+		static bool do_once = true;
+		if (do_once) {
+			WARN(1, "%s: Dropped data frame as no usable bitrate found while scanning and associated. Target station: %pM on %d GHz band\n",
+			     tx->sdata->name, hdr->addr1,
+			     info->band ? 5 : 2);
+			do_once = false;
+		} else {
+			net_info_ratelimited("%s: Dropped data frame as no usable bitrate found while scanning and associated. Target station: %pM on %d GHz band\n",
+					     tx->sdata->name, hdr->addr1,
+					     info->band ? 5 : 2);
+		}
 		return TX_DROP;
+	}
 
 	/*
 	 * If we're associated with the sta at this point we know we can at
-- 
1.7.3.4


^ permalink raw reply related

* [WT PATCH 1/6] mac80211: Add debugfs file to show station-hash counts.
From: greearb @ 2013-06-29 22:58 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear

From: Ben Greear <greearb@candelatech.com>

Helps debug bad hash spreads, like when you have lots of
station interfaces all connected to the same AP.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/mac80211/debugfs.c |   37 +++++++++++++++++++++++++++++++++++++
 1 files changed, 37 insertions(+), 0 deletions(-)

diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index b0e32d6..2bbe377 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -175,8 +175,44 @@ static ssize_t queues_read(struct file *file, char __user *user_buf,
 	return simple_read_from_buffer(user_buf, count, ppos, buf, res);
 }
 
+static ssize_t sta_hash_read(struct file *file, char __user *user_buf,
+			     size_t count, loff_t *ppos)
+{
+	struct ieee80211_local *local = file->private_data;
+	int mxln = STA_HASH_SIZE * 10;
+	char *buf = kzalloc(mxln, GFP_KERNEL);
+	int q, res = 0;
+	struct sta_info *sta;
+
+	if (!buf)
+		return 0;
+
+	mutex_lock(&local->sta_mtx);
+	for (q = 0; q < STA_HASH_SIZE; q++) {
+		int cnt = 0;
+		sta = local->sta_hash[q];
+		while (sta) {
+			cnt++;
+			sta = sta->hnext;
+		}
+		if (cnt) {
+			res += sprintf(buf + res, "%i: %i\n", q, cnt);
+			if (res >= (STA_HASH_SIZE * 10)) {
+				res = STA_HASH_SIZE * 10;
+				break;
+			}
+		}
+	}
+	mutex_unlock(&local->sta_mtx);
+
+	q = simple_read_from_buffer(user_buf, count, ppos, buf, res);
+	kfree(buf);
+	return q;
+}
+
 DEBUGFS_READONLY_FILE_OPS(hwflags);
 DEBUGFS_READONLY_FILE_OPS(queues);
+DEBUGFS_READONLY_FILE_OPS(sta_hash);
 
 /* statistics stuff */
 
@@ -245,6 +281,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
 	DEBUGFS_ADD(total_ps_buffered);
 	DEBUGFS_ADD(wep_iv);
 	DEBUGFS_ADD(queues);
+	DEBUGFS_ADD(sta_hash);
 #ifdef CONFIG_PM
 	DEBUGFS_ADD_MODE(reset, 0200);
 #endif
-- 
1.7.3.4


^ permalink raw reply related

* Re: [RFC v2] mac80211: Use libnl-configurable values for retry counts
From: Felix Fietkau @ 2013-06-29 20:08 UTC (permalink / raw)
  To: Jean-Pierre Tosoni; +Cc: linux-wireless
In-Reply-To: <1372351227-25575-1-git-send-email-jp.tosoni@acksys.fr>

On 2013-06-27 6:40 PM, Jean-Pierre Tosoni wrote:
> From: J.P. Tosoni <jp.tosoni@acksys.fr>
> 
> In the rate control algorithms, the maximum retry count is limited by
> a) a constant value obtained from the hardware driver
> b) a constant limit (6ms) on the time allowed for all
>    retries of each frame.
> 
> Replace the retry count by existing configurable values from nl80211.
> Use wiphy->retry_long for frames whose length exceed rts_threshold.
> Use wiphy->retry_short for all other frames.
> Check that the configured value does not exceed driver capabilities.
> Use the new values as soon as the next frame is transmitted.
> 
> Caveat: the retry count for frames sent outside the context of a STA is
> still taken from the hardware driver.
> ---
> What I am seeking with this patch:
> I believe the configuration of the retries will help making recovery
> much faster when an AP (in infrastructure mode) or a peer (in mesh
> mode) suddenly disappears.
I'm all for reducing retries, but I think the way you're applying the
limit is problematic.
If minstrel decides to use many retries for a high rate and you're
simply cutting off all retries that exceed the configured limit, you're
potentially inviting quite a bit of unnecessary packet loss.
I'm planning to remove the use of retry rate slot 4 (fallback to lowest
rate) from minstrel, since max_prob_rate should already provide quite
decent reliability.

- Felix

^ permalink raw reply

* Re: [rt2x00-users] [PATCH 00/19] rt2x00: add experimental support for RT3593
From: Andreas Hartmann @ 2013-06-29 15:04 UTC (permalink / raw)
  To: Gabor Juhos, John Linville; +Cc: linux-wireless, users
In-Reply-To: <1372446753-11408-1-git-send-email-juhosg@openwrt.org>

Hello Gabor,

Gabor Juhos wrote:
> This patch-set implements experiemental support for the
> RT3593 chipset. The patches are tested on the Linksys
> AE3000 USB device only, however other USB devices which
> are using the RT3573 chips might work as well.


I tested your patchset (and all the others) with the same device you
used for developing in a real life scenario. My AP
http://wikidevi.com/wiki/TP-LINK_TL-WDN4800 is configured for 2.4 GHz,
40MHz, 802.11n, EAP-TLS.

The AE3000 is used with a notebook / core i5 processor.

The test was done *during a parallel running full hd video* in the
same net with another AE3000 running on raspberry pi with ralinks own
driver *always w/o any stuttering* (that's why I'm buying such devices)!
There is a reinforced-concrete floor between AP and the STAs.

>From /var/log/messages:

kernel: [33425.890174] cfg80211: Calling CRDA to update world regulatory domain
kernel: [33425.894221] cfg80211: World regulatory domain updated:
kernel: [33425.894230] cfg80211:   (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
kernel: [33425.894232] cfg80211:   (2402000 KHz - 2472000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
kernel: [33425.894234] cfg80211:   (2457000 KHz - 2482000 KHz @ 20000 KHz), (300 mBi, 2000 mBm)
kernel: [33425.894236] cfg80211:   (2474000 KHz - 2494000 KHz @ 20000 KHz), (300 mBi, 2000 mBm)
kernel: [33425.894238] cfg80211:   (5170000 KHz - 5250000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
kernel: [33425.894240] cfg80211:   (5735000 KHz - 5835000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
kernel: [33425.973578] usb 2-1.5: reset high-speed USB device number 3 using ehci-pci
kernel: [33426.070273] ieee80211 phy0: rt2x00_set_rt: Info - RT chipset 3593, rev 0402 detected
kernel: [33426.102833] ieee80211 phy0: rt2x00_set_rf: Info - RF chipset 000d detected
kernel: [33426.103387] ieee80211 phy0: Selected rate control algorithm 'minstrel_ht'
kernel: [33426.104122] usbcore: registered new interface driver rt2800usb
kernel: [33429.115258] ieee80211 phy0: rt2x00lib_request_firmware: Info - Loading firmware file 'rt2870.bin'
kernel: [33429.115305] ieee80211 phy0: rt2x00lib_request_firmware: Info - Firmware detected - version: 0.33
kernel: [33429.359196] IPv6: ADDRCONF(NETDEV_UP): wlan2: link is not ready
kernel: [33432.884764] wlan2: authenticate with 11:22:33:44:55:66
kernel: [33432.937069] wlan2: send auth to 11:22:33:44:55:66 (try 1/3)
kernel: [33432.939615] wlan2: authenticated
kernel: [33432.940177] wlan2: associate with 11:22:33:44:55:66 (try 1/3)
kernel: [33432.943876] wlan2: RX AssocResp from 11:22:33:44:55:66 (capab=0x431 status=0 aid=1)
kernel: [33432.953244] wlan2: associated
kernel: [33432.953278] IPv6: ADDRCONF(NETDEV_CHANGE): wlan2: link becomes ready
kernel: [33432.953322] cfg80211: Calling CRDA for country: DE
kernel: [33432.957301] cfg80211: Regulatory domain changed to country: DE
kernel: [33432.957306] cfg80211:   (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
kernel: [33432.957310] cfg80211:   (2400000 KHz - 2483500 KHz @ 40000 KHz), (N/A, 2000 mBm)
kernel: [33432.957313] cfg80211:   (5150000 KHz - 5250000 KHz @ 40000 KHz), (N/A, 2000 mBm)
kernel: [33432.957316] cfg80211:   (5250000 KHz - 5350000 KHz @ 40000 KHz), (N/A, 2000 mBm)
kernel: [33432.957319] cfg80211:   (5470000 KHz - 5725000 KHz @ 40000 KHz), (N/A, 2698 mBm)


netperf gives with rt2800usb on the notebook:

MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to server () port 0 AF_INET : demo
enable_enobufs failed: setsockopt
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.01      78.41   
MIGRATED TCP MAERTS TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET from server () port 0 AF_INET : demo
enable_enobufs failed: setsockopt
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.00     115.92   
TCP SENDFILE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to server () port 0 AF_INET : demo
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.02      86.46



The exactly same (=unchanged conditions) done with
DPO_RT5572_LinuxSTA_2.6.1.3_20121022 on the notebook gives:


MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to server () port 0 AF_INET : demo
enable_enobufs failed: setsockopt
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.02     130.36   
MIGRATED TCP MAERTS TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET from server () port 0 AF_INET : demo
enable_enobufs failed: setsockopt
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.00     131.23   
TCP SENDFILE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to server () port 0 AF_INET : demo
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.03     131.33



Thanks,
kind regards,
Andreas

^ permalink raw reply

* Re: [PATCH 19/19] rt2x00: rt2800usb: add USB device ID for Linksys AE3000
From: Gabor Juhos @ 2013-06-29 11:38 UTC (permalink / raw)
  To: Xose Vazquez Perez; +Cc: users@rt2x00.serialmonkey.com, linux-wireless
In-Reply-To: <51CE0DA4.7090608@gmail.com>

2013.06.29. 0:26 keltezéssel, Xose Vazquez Perez írta:
> Gabor Juhos wrote:
> 
>> diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
>> index c24c1fd..6136871 100644
>> --- a/drivers/net/wireless/rt2x00/rt2800usb.c
>> +++ b/drivers/net/wireless/rt2x00/rt2800usb.c
>> @@ -1183,6 +1183,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
>>  	{ USB_DEVICE(0x04bb, 0x0944) },
>>  	/* Linksys */
>>  	{ USB_DEVICE(0x13b1, 0x002f) },
>> +	{ USB_DEVICE(0x13b1, 0x003b) },
>>  	{ USB_DEVICE(0x1737, 0x0079) },
>>  	/* Ralink */
>>  	{ USB_DEVICE(0x148f, 0x3572) },
>> -- 
> 
> You should separate RT3573 and RT3572 devices.
> Rename CONFIG_RT2800USB_RT35XX to CONFIG_RT2800USB_RT3572
> and do a new CONFIG_RT2800USB_RT3573 section.

Renaming a config option is not a good idea IMO. I would simply add a
CONFIG_RT2800USB_RT3573 symbol which depends on CONFIG_RT2800USB_RT35XX instead.

> And also you can add safely this usb-ids. All of them
> are RT3573 devices:
> 
> 0x1b75, 0x7733 AirLive 450Mbps Wireless-N Dual Band USB Adapter
> 0x0b05, 0x17bc ASUS USB-N66 450Mbps Dual Band USB Adapter
> 0x0b05, 0x17ad ASUS USB-N66 Dual Band N Network Adapter
> 0x050d, 0x1103 Belkin Wireless Adapter
> 0x148f, 0xf301 Cameo Ralink3573 3x3 single band USB dongle
> 0x7392, 0x7733 Edimax
> 0x0e66, 0x0020 Hawking HD45U Dual Band USB Wireless-N Adapter
> 0x0e66, 0x0021 Hawking HD45U Dual Band Wls-450N Adapter
> 0x04bb, 0x094e I-O DATA WN-AG450U Wireless LAN Adapter
> 0x0789, 0x016b Logitec LAN-W450AN/U2
> 0x0846, 0x9012 NETGEAR WNDA4100 N900 Wireless Dual Band USB Adapter
> 0x0846, 0x9019 NETGEAR WNDA4200D Wireless Dual Band USB Adapter
> 0x2019, 0xed19 Planex GW-USDual450
> 0x148f, 0x3573 Ralink 802.11n USB Wireless LAN Card
> 0x0df6, 0x0067 Sitecom Wireless Dualband Network Adapter N750 X6
> 0x0df6, 0x006a Sitecom Wireless Dualband Network Adapter N900 X7
> 0x0586, 0x3421 ZyXEL Dual-Band Wireless N450 USB Adapter

I did not test any of these devices and I don't even know from where did you get
these IDs. Only a subset of these IDs is present in the Ralink driver.

If you feel that all of these can be added safely, you can send a follow-up patch.

-Gabor

^ permalink raw reply

* Re: [PATCH 02/19] rt2x00: rt2800lib: add RFCSR register initialization for RT3593
From: Gabor Juhos @ 2013-06-29 11:17 UTC (permalink / raw)
  To: Xose Vazquez Perez; +Cc: linux-wireless, users@rt2x00.serialmonkey.com
In-Reply-To: <51CE0330.7090007@gmail.com>

2013.06.28. 23:42 keltezéssel, Xose Vazquez Perez írta:
> Gabor Juhos wrote:
> 
>> Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629
>> driver.
> 
> There is a more recent version: DPO_RT5572_LinuxSTA_2.6.1.3_20121022

Yes, I know. However I wanted to test AP mode with the vendor driver and that is
only supported in the '2.6.0.1_20120629' version.

> 
>> diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
>> index 32ecd1a..0041b2c 100644
>> --- a/drivers/net/wireless/rt2x00/rt2800lib.c
>> +++ b/drivers/net/wireless/rt2x00/rt2800lib.c
>> [...]
>> +	/* Initialize default register values */
>> +	rt2800_rfcsr_write(rt2x00dev, 1, 0x03);
>> +	rt2800_rfcsr_write(rt2x00dev, 3, 0x80);
> 
> from ./20120911_RT3573_Linux_STA_v2.5.0.0_Rev1_DPO/chips/rt3593.c
> 
> {RF_R02,                0x80}
> 
> but it was deleted in ./DPO_RT5572_LinuxSTA_2.6.1.3_20121022/chips/rt3593.c
> 
> Was it deliberate ? or a mistake ??

It is intentional. The patch is based on the *2.6.0.1* driver, and the value is
not present in that.

-Gabor



^ permalink raw reply

* Re: [rt2x00-users] [PATCH 01/19] rt2x00: rt2800lib: add BBP register initialization for RT3593
From: Gabor Juhos @ 2013-06-29 11:18 UTC (permalink / raw)
  To: Andreas Hartmann; +Cc: John Linville, linux-wireless, users
In-Reply-To: <51CE6FB5.2000706@01019freenet.de>

[-- Attachment #1: Type: text/plain, Size: 1947 bytes --]

Hi Adnreas,

> thanks for your submission. I tried to test it, but stuck at the problem
> mentioned below.
> 
> 
> Regards,
> Andreas
> 
> Gabor Juhos wrote:
>> Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629
>> driver.
>>
>> References:
>>   NICInitRT3593BbpRegisters in chips/rt3593.c
>>   NICInitBBP in common/rtmp_init.c
>>   NICInitAsicFromEEPROM in common/rtmp_init.c
>>
>> Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
>> ---
>>  drivers/net/wireless/rt2x00/rt2800lib.c |   19 +++++++++++++++++++
>>  1 file changed, 19 insertions(+)
>>
>> diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
>> index 6f58ceb..32ecd1a 100644
>> --- a/drivers/net/wireless/rt2x00/rt2800lib.c
>> +++ b/drivers/net/wireless/rt2x00/rt2800lib.c
>> @@ -4505,6 +4505,22 @@ static void rt2800_init_bbp_3572(struct rt2x00_dev *rt2x00dev)
>>  	rt2800_disable_unused_dac_adc(rt2x00dev);
>>  }
>>  
>> +static void rt2800_init_bbp_3593(struct rt2x00_dev *rt2x00dev)
>> +{
>> +	rt2800_init_bbp_early(rt2x00dev);
>> +
>> +	rt2800_bbp_write(rt2x00dev, 79, 0x13);
>> +	rt2800_bbp_write(rt2x00dev, 80, 0x05);
>> +	rt2800_bbp_write(rt2x00dev, 81, 0x33);
>> +	rt2800_bbp_write(rt2x00dev, 137, 0x0f);
>> +
>> +	rt2800_bbp_write(rt2x00dev, 84, 0x19);
>> +
>> +	/* Enable DC filter */
>> +	if (rt2x00_rt_rev_gte(rt2x00dev, RT3593, REV_RT3593E))
> 
> Where is REV_RT3593E defined?
> 
> /tmp/backports-20130617/drivers/net/wireless/rt2x00/rt2800lib.c: In
> function ‘rt2800_init_bbp_3593’:
> /tmp/backports-20130617/drivers/net/wireless/rt2x00/rt2800lib.c:5325:43:
> error: ‘REV_RT3593E’ undeclared (first use in this function)

You are right, the patch-set should have contained 20 patches, but the first one
is missing. I will post that along with the second version of the series.

However if you want to try it in the meantime, you can find the patch in the
attachment. It must be applied before the other patches.

-Gabor

[-- Attachment #2: 0001-rt2x00-rt2800lib-add-MAC-register-initialization-for.patch --]
[-- Type: text/x-patch, Size: 2227 bytes --]

>From 9afda5e728c713da1a3e55ba0860a3705e5a2cd6 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Thu, 9 May 2013 14:20:09 +0200
Subject: [PATCH v2 01/20] rt2x00: rt2800lib: add MAC register initialization
 for RT3593

Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629
driver.

Reference:
  NICInitRT3593MacRegisters in chips/rt3593.c

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
 drivers/net/wireless/rt2x00/rt2800.h    |    1 +
 drivers/net/wireless/rt2x00/rt2800lib.c |   17 +++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 9216834..02bc80d 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -88,6 +88,7 @@
 #define REV_RT3071E			0x0211
 #define REV_RT3090E			0x0211
 #define REV_RT3390E			0x0211
+#define REV_RT3593E			0x0211
 #define REV_RT5390F			0x0502
 #define REV_RT5390R			0x1502
 #define REV_RT5592C			0x0221
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 7b216f9..6f58ceb 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -3715,6 +3715,23 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 	} else if (rt2x00_rt(rt2x00dev, RT3572)) {
 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
 		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
+	} else if (rt2x00_rt(rt2x00dev, RT3593)) {
+		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000402);
+		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
+		if (rt2x00_rt_rev_lt(rt2x00dev, RT3593, REV_RT3593E)) {
+			rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1,
+					   &eeprom);
+			if (rt2x00_get_field16(eeprom,
+					       EEPROM_NIC_CONF1_DAC_TEST))
+				rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+						      0x0000001f);
+			else
+				rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+						      0x0000000f);
+		} else {
+			rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+					      0x00000000);
+		}
 	} else if (rt2x00_rt(rt2x00dev, RT5390) ||
 		   rt2x00_rt(rt2x00dev, RT5392) ||
 		   rt2x00_rt(rt2x00dev, RT5592)) {
-- 
1.7.10


^ permalink raw reply related

* Re: [rt2x00-users] [PATCH 01/19] rt2x00: rt2800lib: add BBP register initialization for RT3593
From: Andreas Hartmann @ 2013-06-29  5:25 UTC (permalink / raw)
  To: Gabor Juhos, John Linville; +Cc: linux-wireless, users
In-Reply-To: <1372446753-11408-2-git-send-email-juhosg@openwrt.org>

Hi Gabor,

thanks for your submission. I tried to test it, but stuck at the problem
mentioned below.


Regards,
Andreas

Gabor Juhos wrote:
> Based on the Ralink DPO_RT5572_LinuxSTA_2.6.0.1_20120629
> driver.
> 
> References:
>   NICInitRT3593BbpRegisters in chips/rt3593.c
>   NICInitBBP in common/rtmp_init.c
>   NICInitAsicFromEEPROM in common/rtmp_init.c
> 
> Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
> ---
>  drivers/net/wireless/rt2x00/rt2800lib.c |   19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
> index 6f58ceb..32ecd1a 100644
> --- a/drivers/net/wireless/rt2x00/rt2800lib.c
> +++ b/drivers/net/wireless/rt2x00/rt2800lib.c
> @@ -4505,6 +4505,22 @@ static void rt2800_init_bbp_3572(struct rt2x00_dev *rt2x00dev)
>  	rt2800_disable_unused_dac_adc(rt2x00dev);
>  }
>  
> +static void rt2800_init_bbp_3593(struct rt2x00_dev *rt2x00dev)
> +{
> +	rt2800_init_bbp_early(rt2x00dev);
> +
> +	rt2800_bbp_write(rt2x00dev, 79, 0x13);
> +	rt2800_bbp_write(rt2x00dev, 80, 0x05);
> +	rt2800_bbp_write(rt2x00dev, 81, 0x33);
> +	rt2800_bbp_write(rt2x00dev, 137, 0x0f);
> +
> +	rt2800_bbp_write(rt2x00dev, 84, 0x19);
> +
> +	/* Enable DC filter */
> +	if (rt2x00_rt_rev_gte(rt2x00dev, RT3593, REV_RT3593E))

Where is REV_RT3593E defined?

/tmp/backports-20130617/drivers/net/wireless/rt2x00/rt2800lib.c: In
function ‘rt2800_init_bbp_3593’:
/tmp/backports-20130617/drivers/net/wireless/rt2x00/rt2800lib.c:5325:43:
error: ‘REV_RT3593E’ undeclared (first use in this function)


Thanks,
Andreas

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox