2010-12-13 11:40:03

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 01/17] rt2x00: Add rt2800 EEPROM definition

From: RA-Jay Hung <[email protected]>

Add and modify NIC Configuration and LED definition of EEPROM

Signed-off-by: RA-Jay Hung <[email protected]>
Acked-by: Gertjan van Wingerde <[email protected]>
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2800.h | 94 +++++++++++++++++---------
drivers/net/wireless/rt2x00/rt2800lib.c | 111 ++++++++++++++++---------------
2 files changed, 119 insertions(+), 86 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index a81c437..9dcbf87 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -1841,32 +1841,51 @@ struct mac_iveiv_entry {
#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)

/*
- * EEPROM ANTENNA config
+ * EEPROM NIC Configuration 0
* RXPATH: 1: 1R, 2: 2R, 3: 3R
- * TXPATH: 1: 1T, 2: 2T
- */
-#define EEPROM_ANTENNA 0x001a
-#define EEPROM_ANTENNA_RXPATH FIELD16(0x000f)
-#define EEPROM_ANTENNA_TXPATH FIELD16(0x00f0)
-#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0f00)
-
-/*
- * EEPROM NIC config
- * CARDBUS_ACCEL: 0 - enable, 1 - disable
- */
-#define EEPROM_NIC 0x001b
-#define EEPROM_NIC_HW_RADIO FIELD16(0x0001)
-#define EEPROM_NIC_DYNAMIC_TX_AGC FIELD16(0x0002)
-#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0004)
-#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0008)
-#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0010)
-#define EEPROM_NIC_BW40M_SB_BG FIELD16(0x0020)
-#define EEPROM_NIC_BW40M_SB_A FIELD16(0x0040)
-#define EEPROM_NIC_WPS_PBC FIELD16(0x0080)
-#define EEPROM_NIC_BW40M_BG FIELD16(0x0100)
-#define EEPROM_NIC_BW40M_A FIELD16(0x0200)
-#define EEPROM_NIC_ANT_DIVERSITY FIELD16(0x0800)
-#define EEPROM_NIC_DAC_TEST FIELD16(0x8000)
+ * TXPATH: 1: 1T, 2: 2T, 3: 3T
+ * RF_TYPE: RFIC type
+ */
+#define EEPROM_NIC_CONF0 0x001a
+#define EEPROM_NIC_CONF0_RXPATH FIELD16(0x000f)
+#define EEPROM_NIC_CONF0_TXPATH FIELD16(0x00f0)
+#define EEPROM_NIC_CONF0_RF_TYPE FIELD16(0x0f00)
+
+/*
+ * EEPROM NIC Configuration 1
+ * HW_RADIO: 0: disable, 1: enable
+ * EXTERNAL_TX_ALC: 0: disable, 1: enable
+ * EXTERNAL_LNA_2G: 0: disable, 1: enable
+ * EXTERNAL_LNA_5G: 0: disable, 1: enable
+ * CARDBUS_ACCEL: 0: enable, 1: disable
+ * BW40M_SB_2G: 0: disable, 1: enable
+ * BW40M_SB_5G: 0: disable, 1: enable
+ * WPS_PBC: 0: disable, 1: enable
+ * BW40M_2G: 0: enable, 1: disable
+ * BW40M_5G: 0: enable, 1: disable
+ * BROADBAND_EXT_LNA: 0: disable, 1: enable
+ * ANT_DIVERSITY: 00: Disable, 01: Diversity,
+ * 10: Main antenna, 11: Aux antenna
+ * INTERNAL_TX_ALC: 0: disable, 1: enable
+ * BT_COEXIST: 0: disable, 1: enable
+ * DAC_TEST: 0: disable, 1: enable
+ */
+#define EEPROM_NIC_CONF1 0x001b
+#define EEPROM_NIC_CONF1_HW_RADIO FIELD16(0x0001)
+#define EEPROM_NIC_CONF1_EXTERNAL_TX_ALC FIELD16(0x0002)
+#define EEPROM_NIC_CONF1_EXTERNAL_LNA_2G FIELD16(0x0004)
+#define EEPROM_NIC_CONF1_EXTERNAL_LNA_5G FIELD16(0x0008)
+#define EEPROM_NIC_CONF1_CARDBUS_ACCEL FIELD16(0x0010)
+#define EEPROM_NIC_CONF1_BW40M_SB_2G FIELD16(0x0020)
+#define EEPROM_NIC_CONF1_BW40M_SB_5G FIELD16(0x0040)
+#define EEPROM_NIC_CONF1_WPS_PBC FIELD16(0x0080)
+#define EEPROM_NIC_CONF1_BW40M_2G FIELD16(0x0100)
+#define EEPROM_NIC_CONF1_BW40M_5G FIELD16(0x0200)
+#define EEPROM_NIC_CONF1_BROADBAND_EXT_LNA FIELD16(0x400)
+#define EEPROM_NIC_CONF1_ANT_DIVERSITY FIELD16(0x1800)
+#define EEPROM_NIC_CONF1_INTERNAL_TX_ALC FIELD16(0x2000)
+#define EEPROM_NIC_CONF1_BT_COEXIST FIELD16(0x4000)
+#define EEPROM_NIC_CONF1_DAC_TEST FIELD16(0x8000)

/*
* EEPROM frequency
@@ -1888,9 +1907,9 @@ struct mac_iveiv_entry {
* POLARITY_GPIO_4: Polarity GPIO4 setting.
* LED_MODE: Led mode.
*/
-#define EEPROM_LED1 0x001e
-#define EEPROM_LED2 0x001f
-#define EEPROM_LED3 0x0020
+#define EEPROM_LED_AG_CONF 0x001e
+#define EEPROM_LED_ACT_CONF 0x001f
+#define EEPROM_LED_POLARITY 0x0020
#define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001)
#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002)
#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004)
@@ -1902,6 +1921,17 @@ struct mac_iveiv_entry {
#define EEPROM_LED_LED_MODE FIELD16(0x1f00)

/*
+ * EEPROM NIC Configuration 2
+ * RX_STREAM: 0: Reserved, 1: 1 Stream, 2: 2 Stream
+ * TX_STREAM: 0: Reserved, 1: 1 Stream, 2: 2 Stream
+ * CRYSTAL: 00: Reserved, 01: One crystal, 10: Two crystal, 11: Reserved
+ */
+#define EEPROM_NIC_CONF2 0x0021
+#define EEPROM_NIC_CONF2_RX_STREAM FIELD16(0x000f)
+#define EEPROM_NIC_CONF2_TX_STREAM FIELD16(0x00f0)
+#define EEPROM_NIC_CONF2_CRYSTAL FIELD16(0x0600)
+
+/*
* EEPROM LNA
*/
#define EEPROM_LNA 0x0022
@@ -1951,7 +1981,7 @@ struct mac_iveiv_entry {

/*
* EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power.
- * This is delta in 40MHZ.
+ * This is delta in 40MHZ.
* VALUE: Tx Power dalta value (MAX=4)
* TYPE: 1: Plus the delta value, 0: minus the delta value
* TXPOWER: Enable:
@@ -2007,9 +2037,9 @@ struct mac_iveiv_entry {
#define MCU_CURRENT 0x36
#define MCU_LED 0x50
#define MCU_LED_STRENGTH 0x51
-#define MCU_LED_1 0x52
-#define MCU_LED_2 0x53
-#define MCU_LED_3 0x54
+#define MCU_LED_AG_CONF 0x52
+#define MCU_LED_ACT_CONF 0x53
+#define MCU_LED_LED_POLARITY 0x54
#define MCU_RADAR 0x60
#define MCU_BOOT_SIGNAL 0x72
#define MCU_BBP_SIGNAL 0x80
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 7563161..9b592d9 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1930,8 +1930,8 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_DAC_TEST))
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
rt2800_register_write(rt2x00dev, TX_SW_CFG2,
0x0000002c);
else
@@ -2376,10 +2376,10 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
rt2x00_rt(rt2x00dev, RT3390)) {
rt2800_bbp_read(rt2x00dev, 138, &value);

- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1)
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
value |= 0x20;
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1)
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
value &= ~0x02;

rt2800_bbp_write(rt2x00dev, 138, value);
@@ -2591,8 +2591,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) {
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_DAC_TEST))
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
else
rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
@@ -2665,10 +2665,10 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt(rt2x00dev, RT3090)) {
rt2800_bbp_read(rt2x00dev, 138, &bbp);

- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1)
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0);
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1)
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
rt2x00_set_field8(&bbp, BBP138_TX_DAC1, 1);

rt2800_bbp_write(rt2x00dev, 138, bbp);
@@ -2767,16 +2767,16 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Initialize LED control
*/
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_AG_CONF, 0xff,
word & 0xff, (word >> 8) & 0xff);

- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_ACT_CONF, 0xff,
word & 0xff, (word >> 8) & 0xff);

- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_LED_POLARITY, 0xff,
word & 0xff, (word >> 8) & 0xff);

return 0;
@@ -2870,38 +2870,41 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}

- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &word);
if (word == 0xffff) {
- rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
- rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1);
- rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_TXPATH, 1);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RF_TYPE, RF2820);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
} else if (rt2x00_rt(rt2x00dev, RT2860) ||
rt2x00_rt(rt2x00dev, RT2872)) {
/*
* There is a max of 2 RX streams for RT28x0 series
*/
- if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2)
- rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ if (rt2x00_get_field16(word, EEPROM_NIC_CONF0_RXPATH) > 2)
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
}

- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &word);
if (word == 0xffff) {
- rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_ANT_DIVERSITY, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_DAC_TEST, 0);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_HW_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_CARDBUS_ACCEL, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_SB_2G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_SB_5G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_WPS_PBC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_2G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_5G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BROADBAND_EXT_LNA, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_ANT_DIVERSITY, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_INTERNAL_TX_ALC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BT_COEXIST, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_DAC_TEST, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF1, word);
EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
}

@@ -2916,9 +2919,9 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
LED_MODE_TXRX_ACTIVITY);
rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_AG_CONF, 0x5555);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_ACT_CONF, 0x2221);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_POLARITY, 0xa9f8);
EEPROM(rt2x00dev, "Led Mode: 0x%04x\n", word);
}

@@ -2982,12 +2985,12 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Read EEPROM word for configuration.
*/
- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);

/*
* Identify RF chipset.
*/
- value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ value = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);

rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
@@ -3023,9 +3026,9 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Identify default antenna configuration.
*/
rt2x00dev->default_ant.tx =
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH);
+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH);
rt2x00dev->default_ant.rx =
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH);
+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH);

/*
* Read frequency offset and RF programming sequence.
@@ -3036,17 +3039,17 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Read external LNA informations.
*/
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);

- if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G))
__set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G))
__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);

/*
* Detect if this device has an hardware controlled radio.
*/
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_HW_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);

/*
@@ -3258,7 +3261,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
rt2x00dev->hw->max_report_rates = 7;
rt2x00dev->hw->max_rate_tries = 1;

- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);

/*
* Initialize hw_mode information.
@@ -3302,11 +3305,11 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40;

- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) >= 2)
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) >= 2)
spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC;

spec->ht.cap |=
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) <<
+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) <<
IEEE80211_HT_CAP_RX_STBC_SHIFT;

spec->ht.ampdu_factor = 3;
@@ -3314,10 +3317,10 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->ht.mcs.tx_params =
IEEE80211_HT_MCS_TX_DEFINED |
IEEE80211_HT_MCS_TX_RX_DIFF |
- ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) <<
+ ((rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) - 1) <<
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);

- switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) {
+ switch (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH)) {
case 3:
spec->ht.mcs.rx_mask[2] = 0xff;
case 2:
--
1.7.2.3



2010-12-13 11:40:30

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 13/17] rt2x00: Introduce extra queue entry sanity flag

Add a queue entry flag ENTRY_DATA_STATUS_PENDING,
which can be used to indicate a queue entry has
returned from the hardware and is waiting for
status processing. Using this flag we can add
some extra sanity checks to prevent queue corruption.

Signed-off-by: Ivo van Doorn <[email protected]>
Acked-by: Helmut Schaa <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00dev.c | 1 +
drivers/net/wireless/rt2x00/rt2x00queue.h | 6 +++++-
drivers/net/wireless/rt2x00/rt2x00usb.c | 12 ++++++++----
3 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index f3ae949..87a421b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -235,6 +235,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_dmastart);

void rt2x00lib_dmadone(struct queue_entry *entry)
{
+ set_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags);
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index baa39b7..4765934 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -340,12 +340,16 @@ struct txentry_desc {
* @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occured
* while transfering the data to the hardware. No TX status report will
* be expected from the hardware.
+ * @ENTRY_DATA_STATUS_PENDING: The entry has been send to the device and
+ * returned. It is now waiting for the status reporting before the
+ * entry can be reused again.
*/
enum queue_entry_flags {
ENTRY_BCN_ASSIGNED,
ENTRY_OWNER_DEVICE_DATA,
ENTRY_DATA_PENDING,
- ENTRY_DATA_IO_FAILED
+ ENTRY_DATA_IO_FAILED,
+ ENTRY_DATA_STATUS_PENDING,
};

/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index cd29ebc..8a16b51 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -195,7 +195,8 @@ static void rt2x00usb_work_txdone(struct work_struct *work)
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);

- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
break;

rt2x00usb_work_txdone_entry(entry);
@@ -237,7 +238,8 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
u32 length;
int status;

- if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
+ if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) ||
+ test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
return;

/*
@@ -275,7 +277,8 @@ static void rt2x00usb_work_rxdone(struct work_struct *work)
while (!rt2x00queue_empty(rt2x00dev->rx)) {
entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE);

- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
break;

/*
@@ -327,7 +330,8 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
int status;

- if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
return;

rt2x00lib_dmastart(entry);
--
1.7.2.3


2010-12-13 11:40:06

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 02/17] rt2x00: Implement get_survey callback for rt2800

From: Helmut Schaa <[email protected]>

Implement the get_survey callback to allow user space to read statistics
about the current channel condition.

Signed-off-by: Helmut Schaa <[email protected]>
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2800.h | 10 ++++++
drivers/net/wireless/rt2x00/rt2800lib.c | 49 +++++++++++++++++++++++++++++++
drivers/net/wireless/rt2x00/rt2800lib.h | 2 +
drivers/net/wireless/rt2x00/rt2800pci.c | 1 +
drivers/net/wireless/rt2x00/rt2800usb.c | 1 +
5 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 9dcbf87..03f9fa1 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -699,8 +699,18 @@

/*
* CH_TIME_CFG: count as channel busy
+ * EIFS_BUSY: Count EIFS as channel busy
+ * NAV_BUSY: Count NAS as channel busy
+ * RX_BUSY: Count RX as channel busy
+ * TX_BUSY: Count TX as channel busy
+ * TMR_EN: Enable channel statistics timer
*/
#define CH_TIME_CFG 0x110c
+#define CH_TIME_CFG_EIFS_BUSY FIELD32(0x00000010)
+#define CH_TIME_CFG_NAV_BUSY FIELD32(0x00000008)
+#define CH_TIME_CFG_RX_BUSY FIELD32(0x00000004)
+#define CH_TIME_CFG_TX_BUSY FIELD32(0x00000002)
+#define CH_TIME_CFG_TMR_EN FIELD32(0x00000001)

/*
* PBF_LIFE_TIMER: TX/RX MPDU timestamp timer (free run) Unit: 1us
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 9b592d9..b7de1a5 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1625,6 +1625,13 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
}

msleep(1);
+
+ /*
+ * Clear channel statistic counters
+ */
+ rt2800_register_read(rt2x00dev, CH_IDLE_STA, &reg);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA, &reg);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &reg);
}

static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
@@ -2259,6 +2266,17 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, INT_TIMER_CFG_PRE_TBTT_TIMER, 6 << 4);
rt2800_register_write(rt2x00dev, INT_TIMER_CFG, reg);

+ /*
+ * Set up channel statistics timer
+ */
+ rt2800_register_read(rt2x00dev, CH_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_EIFS_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_NAV_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_RX_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_TX_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_TMR_EN, 1);
+ rt2800_register_write(rt2x00dev, CH_TIME_CFG, reg);
+
return 0;
}

@@ -3539,6 +3557,37 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
EXPORT_SYMBOL_GPL(rt2800_ampdu_action);

+int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+ u32 idle, busy, busy_ext;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ survey->channel = conf->channel;
+
+ rt2800_register_read(rt2x00dev, CH_IDLE_STA, &idle);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA, &busy);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext);
+
+ if (idle || busy) {
+ survey->filled = SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY |
+ SURVEY_INFO_CHANNEL_TIME_EXT_BUSY;
+
+ survey->channel_time = (idle + busy) / 1000;
+ survey->channel_time_busy = busy / 1000;
+ survey->channel_time_ext_busy = busy_ext / 1000;
+ }
+
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(rt2800_get_survey);
+
MODULE_AUTHOR(DRV_PROJECT ", Bartlomiej Zolnierkiewicz");
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("Ralink RT2800 library");
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 81cbc92..e3c995a 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -199,5 +199,7 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw);
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey);

#endif /* RT2800LIB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 433c7f3..3a1468a 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -943,6 +943,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
.rfkill_poll = rt2x00mac_rfkill_poll,
.ampdu_action = rt2800_ampdu_action,
.flush = rt2x00mac_flush,
+ .get_survey = rt2800_get_survey,
};

static const struct rt2800_ops rt2800pci_rt2800_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 935b76d..042e47d 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -562,6 +562,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.rfkill_poll = rt2x00mac_rfkill_poll,
.ampdu_action = rt2800_ampdu_action,
.flush = rt2x00mac_flush,
+ .get_survey = rt2800_get_survey,
};

static const struct rt2800_ops rt2800usb_rt2800_ops = {
--
1.7.2.3


2010-12-13 11:40:24

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 09/17] rt2x00: Reorganize queue callback functions

As part of the queue refactoring, change the queue callback
function names to have 3 different actions: start, kick & stop.

We can now also remove the STATE_RADIO_RX_ON/STATE_RADIO_RX_OFF
device_state flags, and replace the usage with using the
start_queue/stop_queue callback functions.
This streamlines the RX queue handling to the
similar approach as all other queues.

Signed-off-by: Ivo van Doorn <[email protected]>
Acked-by: Helmut Schaa <[email protected]>
---
drivers/net/wireless/rt2x00/rt2400pci.c | 11 +++--------
drivers/net/wireless/rt2x00/rt2500pci.c | 11 +++--------
drivers/net/wireless/rt2x00/rt2500usb.c | 11 +++--------
drivers/net/wireless/rt2x00/rt2800pci.c | 11 +++--------
drivers/net/wireless/rt2x00/rt2800usb.c | 11 +++--------
drivers/net/wireless/rt2x00/rt2x00.h | 9 +++++++--
drivers/net/wireless/rt2x00/rt2x00config.c | 6 ++----
drivers/net/wireless/rt2x00/rt2x00dev.c | 4 ++--
drivers/net/wireless/rt2x00/rt2x00mac.c | 6 +++---
drivers/net/wireless/rt2x00/rt2x00queue.c | 6 +++---
drivers/net/wireless/rt2x00/rt2x00reg.h | 2 --
drivers/net/wireless/rt2x00/rt2x00usb.c | 24 +++++++++++++++---------
drivers/net/wireless/rt2x00/rt2x00usb.h | 4 ++--
drivers/net/wireless/rt2x00/rt61pci.c | 11 +++--------
drivers/net/wireless/rt2x00/rt73usb.c | 11 +++--------
15 files changed, 55 insertions(+), 83 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 35d9a06..2fc6ca5 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1058,12 +1058,6 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt2400pci_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- rt2400pci_start_queue(rt2x00dev->rx);
- break;
- case STATE_RADIO_RX_OFF:
- rt2400pci_stop_queue(rt2x00dev->rx);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1672,10 +1666,11 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.link_stats = rt2400pci_link_stats,
.reset_tuner = rt2400pci_reset_tuner,
.link_tuner = rt2400pci_link_tuner,
+ .start_queue = rt2400pci_start_queue,
+ .kick_queue = rt2400pci_kick_queue,
+ .stop_queue = rt2400pci_stop_queue,
.write_tx_desc = rt2400pci_write_tx_desc,
.write_beacon = rt2400pci_write_beacon,
- .kick_tx_queue = rt2400pci_kick_queue,
- .kill_tx_queue = rt2400pci_stop_queue,
.fill_rxdone = rt2400pci_fill_rxdone,
.config_filter = rt2400pci_config_filter,
.config_intf = rt2400pci_config_intf,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index bee7ce1..d67f911 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1213,12 +1213,6 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt2500pci_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- rt2500pci_start_queue(rt2x00dev->rx);
- break;
- case STATE_RADIO_RX_OFF:
- rt2500pci_stop_queue(rt2x00dev->rx);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1969,10 +1963,11 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.link_stats = rt2500pci_link_stats,
.reset_tuner = rt2500pci_reset_tuner,
.link_tuner = rt2500pci_link_tuner,
+ .start_queue = rt2500pci_start_queue,
+ .kick_queue = rt2500pci_kick_queue,
+ .stop_queue = rt2500pci_stop_queue,
.write_tx_desc = rt2500pci_write_tx_desc,
.write_beacon = rt2500pci_write_beacon,
- .kick_tx_queue = rt2500pci_kick_queue,
- .kill_tx_queue = rt2500pci_stop_queue,
.fill_rxdone = rt2500pci_fill_rxdone,
.config_filter = rt2500pci_config_filter,
.config_intf = rt2500pci_config_intf,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 52bd0ed..a56b38f 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1057,12 +1057,6 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt2500usb_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- rt2500usb_start_queue(rt2x00dev->rx);
- break;
- case STATE_RADIO_RX_OFF:
- rt2500usb_stop_queue(rt2x00dev->rx);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1845,11 +1839,12 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.link_stats = rt2500usb_link_stats,
.reset_tuner = rt2500usb_reset_tuner,
.watchdog = rt2x00usb_watchdog,
+ .start_queue = rt2500usb_start_queue,
+ .kick_queue = rt2x00usb_kick_queue,
+ .stop_queue = rt2500usb_stop_queue,
.write_tx_desc = rt2500usb_write_tx_desc,
.write_beacon = rt2500usb_write_beacon,
.get_tx_data_len = rt2500usb_get_tx_data_len,
- .kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt2500usb_stop_queue,
.fill_rxdone = rt2500usb_fill_rxdone,
.config_shared_key = rt2500usb_config_key,
.config_pairwise_key = rt2500usb_config_key,
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 08b55b5..195f0be3 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -537,12 +537,6 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800pci_disable_radio(rt2x00dev);
rt2800pci_set_state(rt2x00dev, STATE_SLEEP);
break;
- case STATE_RADIO_RX_ON:
- rt2800pci_start_queue(rt2x00dev->rx);
- break;
- case STATE_RADIO_RX_OFF:
- rt2800pci_stop_queue(rt2x00dev->rx);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1003,11 +997,12 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.link_stats = rt2800_link_stats,
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
+ .start_queue = rt2800pci_start_queue,
+ .kick_queue = rt2800pci_kick_queue,
+ .stop_queue = rt2800pci_stop_queue,
.write_tx_desc = rt2800pci_write_tx_desc,
.write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
- .kick_tx_queue = rt2800pci_kick_queue,
- .kill_tx_queue = rt2800pci_stop_queue,
.fill_rxdone = rt2800pci_fill_rxdone,
.config_shared_key = rt2800_config_shared_key,
.config_pairwise_key = rt2800_config_pairwise_key,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index ee51936..60b5503 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -254,12 +254,6 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800usb_disable_radio(rt2x00dev);
rt2800usb_set_state(rt2x00dev, STATE_SLEEP);
break;
- case STATE_RADIO_RX_ON:
- rt2800usb_start_queue(rt2x00dev->rx);
- break;
- case STATE_RADIO_RX_OFF:
- rt2800usb_stop_queue(rt2x00dev->rx);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -626,12 +620,13 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
.watchdog = rt2800usb_watchdog,
+ .start_queue = rt2800usb_start_queue,
+ .kick_queue = rt2x00usb_kick_queue,
+ .stop_queue = rt2800usb_stop_queue,
.write_tx_desc = rt2800usb_write_tx_desc,
.write_tx_data = rt2800usb_write_tx_data,
.write_beacon = rt2800_write_beacon,
.get_tx_data_len = rt2800usb_get_tx_data_len,
- .kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt2800usb_stop_queue,
.fill_rxdone = rt2800usb_fill_rxdone,
.config_shared_key = rt2800_config_shared_key,
.config_pairwise_key = rt2800_config_pairwise_key,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 0a55eef..617d68f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -567,7 +567,14 @@ struct rt2x00lib_ops {
struct link_qual *qual);
void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, const u32 count);
+
+ /*
+ * Data queue handlers.
+ */
void (*watchdog) (struct rt2x00_dev *rt2x00dev);
+ void (*start_queue) (struct data_queue *queue);
+ void (*kick_queue) (struct data_queue *queue);
+ void (*stop_queue) (struct data_queue *queue);

/*
* TX control handlers
@@ -579,8 +586,6 @@ struct rt2x00lib_ops {
void (*write_beacon) (struct queue_entry *entry,
struct txentry_desc *txdesc);
int (*get_tx_data_len) (struct queue_entry *entry);
- void (*kick_tx_queue) (struct data_queue *queue);
- void (*kill_tx_queue) (struct data_queue *queue);

/*
* RX control handlers
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index a238e90..d2f1f0a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -146,8 +146,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* else the changes will be ignored by the device.
*/
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2x00dev->ops->lib->set_device_state(rt2x00dev,
- STATE_RADIO_RX_OFF);
+ rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx);

/*
* Write new antenna setup to device and reset the link tuner.
@@ -161,8 +160,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
memcpy(active, &config, sizeof(config));

if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2x00dev->ops->lib->set_device_state(rt2x00dev,
- STATE_RADIO_RX_ON);
+ rt2x00dev->ops->lib->start_queue(rt2x00dev->rx);
}

void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index c879f9a..8d864b6 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -68,7 +68,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Enable RX.
*/
- rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_ON);
+ rt2x00dev->ops->lib->start_queue(rt2x00dev->rx);
rt2x00link_start_tuner(rt2x00dev);

/*
@@ -104,7 +104,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
* Disable RX.
*/
rt2x00link_stop_tuner(rt2x00dev);
- rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_OFF);
+ rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx);

/*
* Disable radio.
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 7ad4b27..6713f1a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -352,7 +352,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
* if for any reason the link tuner must be reset, this will be
* handled by rt2x00lib_config().
*/
- rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_OFF);
+ rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx);

/*
* When we've just turned on the radio, we want to reprogram
@@ -370,7 +370,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);

/* Turn RX back on */
- rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_ON);
+ rt2x00dev->ops->lib->start_queue(rt2x00dev->rx);

return 0;
}
@@ -727,7 +727,7 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
* any pending frames to be transmitted.
*/
tx_queue_for_each(rt2x00dev, queue) {
- rt2x00dev->ops->lib->kick_tx_queue(queue);
+ rt2x00dev->ops->lib->kick_queue(queue);
}

/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 35133d8..2af6cea 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -471,7 +471,7 @@ static void rt2x00queue_kick_tx_queue(struct data_queue *queue,
*/
if (rt2x00queue_threshold(queue) ||
!test_bit(ENTRY_TXD_BURST, &txdesc->flags))
- queue->rt2x00dev->ops->lib->kick_tx_queue(queue);
+ queue->rt2x00dev->ops->lib->kick_queue(queue);
}

int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
@@ -585,7 +585,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
rt2x00queue_free_skb(intf->beacon);

if (!enable_beacon) {
- rt2x00dev->ops->lib->kill_tx_queue(intf->beacon->queue);
+ rt2x00dev->ops->lib->stop_queue(intf->beacon->queue);
mutex_unlock(&intf->beacon_skb_mutex);
return 0;
}
@@ -761,7 +761,7 @@ void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
struct data_queue *queue;

txall_queue_for_each(rt2x00dev, queue)
- rt2x00dev->ops->lib->kill_tx_queue(queue);
+ rt2x00dev->ops->lib->stop_queue(queue);
}

void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index ed71be9..e8259ae 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -83,8 +83,6 @@ enum dev_state {
*/
STATE_RADIO_ON,
STATE_RADIO_OFF,
- STATE_RADIO_RX_ON,
- STATE_RADIO_RX_OFF,
STATE_RADIO_IRQ_ON,
STATE_RADIO_IRQ_OFF,
STATE_RADIO_IRQ_ON_ISR,
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 12958a4..d4361dc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -261,12 +261,22 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
}
}

-void rt2x00usb_kick_tx_queue(struct data_queue *queue)
+void rt2x00usb_kick_queue(struct data_queue *queue)
{
- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
- rt2x00usb_kick_tx_entry);
+ switch (queue->qid) {
+ case QID_AC_BE:
+ case QID_AC_BK:
+ case QID_AC_VI:
+ case QID_AC_VO:
+ if (!rt2x00queue_empty(queue))
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00usb_kick_tx_entry);
+ break;
+ default:
+ break;
+ }
}
-EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);
+EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue);

static void rt2x00usb_kill_entry(struct queue_entry *entry)
{
@@ -422,11 +432,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
REGISTER_TIMEOUT);

- /*
- * The USB version of also works
- * on the RX queue.
- */
- rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev->rx);
+ rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx);
}
EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);

diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 656a35f..05a5424 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -378,13 +378,13 @@ struct queue_entry_priv_usb_bcn {
};

/**
- * rt2x00usb_kick_tx_queue - Kick data queue
+ * rt2x00usb_kick_queue - Kick data queue
* @queue: Data queue to kick
*
* This will walk through all entries of the queue and push all pending
* frames to the hardware as a single burst.
*/
-void rt2x00usb_kick_tx_queue(struct data_queue *queue);
+void rt2x00usb_kick_queue(struct data_queue *queue);

/**
* rt2x00usb_stop_queue - Stop data queue
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 044f500..7156b78 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1832,12 +1832,6 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt61pci_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- rt61pci_start_queue(rt2x00dev->rx);
- break;
- case STATE_RADIO_RX_OFF:
- rt61pci_stop_queue(rt2x00dev->rx);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -2900,10 +2894,11 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.link_stats = rt61pci_link_stats,
.reset_tuner = rt61pci_reset_tuner,
.link_tuner = rt61pci_link_tuner,
+ .start_queue = rt61pci_start_queue,
+ .kick_queue = rt61pci_kick_queue,
+ .stop_queue = rt61pci_stop_queue,
.write_tx_desc = rt61pci_write_tx_desc,
.write_beacon = rt61pci_write_beacon,
- .kick_tx_queue = rt61pci_kick_queue,
- .kill_tx_queue = rt61pci_stop_queue,
.fill_rxdone = rt61pci_fill_rxdone,
.config_shared_key = rt61pci_config_shared_key,
.config_pairwise_key = rt61pci_config_pairwise_key,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index e9b1e3d..f55e74e 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1441,12 +1441,6 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt73usb_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- rt73usb_start_queue(rt2x00dev->rx);
- break;
- case STATE_RADIO_RX_OFF:
- rt73usb_stop_queue(rt2x00dev->rx);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -2312,11 +2306,12 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.reset_tuner = rt73usb_reset_tuner,
.link_tuner = rt73usb_link_tuner,
.watchdog = rt2x00usb_watchdog,
+ .start_queue = rt73usb_start_queue,
+ .kick_queue = rt2x00usb_kick_queue,
+ .stop_queue = rt73usb_stop_queue,
.write_tx_desc = rt73usb_write_tx_desc,
.write_beacon = rt73usb_write_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,
- .kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt73usb_stop_queue,
.fill_rxdone = rt73usb_fill_rxdone,
.config_shared_key = rt73usb_config_shared_key,
.config_pairwise_key = rt73usb_config_pairwise_key,
--
1.7.2.3


2010-12-13 11:40:29

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 12/17] rt2x00: Cleanup RX index counting

Add the rt2x00_dmastart function to rt2x00lib which
marks the queue_entry as "owned by device", and increased
the Q_INDEX number.

This cleanups up the index handling by rt2x00lib which
at until so far used hackish approaches to keep the
RX queue index numbering sane.

The rt2x00pci.c changes are from Helmut Schaa

Signed-off-by: Ivo van Doorn <[email protected]>
Signed-off-by: Helmut Schaa <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00.h | 1 +
drivers/net/wireless/rt2x00/rt2x00dev.c | 11 ++++++++---
drivers/net/wireless/rt2x00/rt2x00pci.c | 7 +++++++
drivers/net/wireless/rt2x00/rt2x00queue.c | 5 +----
drivers/net/wireless/rt2x00/rt2x00usb.c | 2 ++
5 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 520e736..556b744 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -1170,6 +1170,7 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_dmastart(struct queue_entry *entry);
void rt2x00lib_dmadone(struct queue_entry *entry);
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 01c8415..f3ae949 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -226,6 +226,13 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);

+void rt2x00lib_dmastart(struct queue_entry *entry)
+{
+ set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+ rt2x00queue_index_inc(entry->queue, Q_INDEX);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_dmastart);
+
void rt2x00lib_dmadone(struct queue_entry *entry)
{
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
@@ -552,10 +559,8 @@ submit_entry:
entry->flags = 0;
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
- test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) {
+ test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00dev->ops->lib->clear_entry(entry);
- rt2x00queue_index_inc(entry->queue, Q_INDEX);
- }
}
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);

diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 868ca19..28e6ff1 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -82,6 +82,13 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
skbdesc->desc_len = entry->queue->desc_size;

/*
+ * DMA is already done, notify rt2x00lib that
+ * it finished successfully.
+ */
+ rt2x00lib_dmastart(entry);
+ rt2x00lib_dmadone(entry);
+
+ /*
* Send the frame to rt2x00lib for further processing.
*/
rt2x00lib_rxdone(entry);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 313a8fa..52cc92d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -968,11 +968,8 @@ void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
queue_for_each(rt2x00dev, queue) {
rt2x00queue_reset(queue);

- for (i = 0; i < queue->limit; i++) {
+ for (i = 0; i < queue->limit; i++)
rt2x00dev->ops->lib->clear_entry(&queue->entries[i]);
- if (queue->qid == QID_RX)
- rt2x00queue_index_inc(queue, Q_INDEX);
- }
}
}

diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index cd80eec..cd29ebc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -330,6 +330,8 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;

+ rt2x00lib_dmastart(entry);
+
usb_fill_bulk_urb(entry_priv->urb, usb_dev,
usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint),
entry->skb->data, entry->skb->len,
--
1.7.2.3


2010-12-14 18:58:14

by Helmut Schaa

[permalink] [raw]
Subject: Re: [PATCH 14/17] rt2x00: Fix WMM Queue naming

Am Dienstag, 14. Dezember 2010 schrieb Ivo Van Doorn:
> Hi,
>
> >> The Queue names were incorrectly copied from the legacy drivers,
> >> as a result the queue names were inversed to what was expected.
> >>
> >> This renames the queues using this mapping:
> >> QID_AC_BK -> QID_AC_VO (priority 0)
> >> QID_AC_BE -> QID_AC_VI (priority 1)
> >> QID_AC_VI -> QID_AC_BE (priority 2)
> >> QID_AC_VO -> QID_AC_BK (priority 3)
> >>
> >> Note that this was a naming problem only, which didn't affect
> >> the assignment of frames to their respective queues.
> >>
> >> Signed-off-by: Ivo van Doorn <[email protected]>
> >
> > Ivo, due to the latest info from Ralink I'd say we should drop this patch
> > and instead introduce a mac80211_to_rt2x00_qid mapper that maps from
> > ieee80211_ac_numbers to data_queue_qid.
> >
> > This patch doesn't cause any harm, but we would have to revert it partly
> > if we introduce the queue mapping as needed by the rt2x00 devices.
>
> I don't agree, this patch can safely be applied, since the mapping
> is in the endpoint assignment, rather the register value usage,
> I think the more optimal solution is fixing rt2x00usb_assign_endpoints.
> In there it currently assigns endpoints assuming the first endpoint
> is the highest priority, while we should be able to simply swap that
> to invert the logic.

Ah, ok, sounds good to me, at least for USB. Do we need the same for PCI
devices?

Helmut

2010-12-14 17:54:00

by Helmut Schaa

[permalink] [raw]
Subject: Re: [PATCH 14/17] rt2x00: Fix WMM Queue naming

Am Montag, 13. Dezember 2010 schrieb Ivo van Doorn:
> The Queue names were incorrectly copied from the legacy drivers,
> as a result the queue names were inversed to what was expected.
>
> This renames the queues using this mapping:
> QID_AC_BK -> QID_AC_VO (priority 0)
> QID_AC_BE -> QID_AC_VI (priority 1)
> QID_AC_VI -> QID_AC_BE (priority 2)
> QID_AC_VO -> QID_AC_BK (priority 3)
>
> Note that this was a naming problem only, which didn't affect
> the assignment of frames to their respective queues.
>
> Signed-off-by: Ivo van Doorn <[email protected]>

Ivo, due to the latest info from Ralink I'd say we should drop this patch
and instead introduce a mac80211_to_rt2x00_qid mapper that maps from
ieee80211_ac_numbers to data_queue_qid.

This patch doesn't cause any harm, but we would have to revert it partly
if we introduce the queue mapping as needed by the rt2x00 devices.

Thanks,
Helmut

> ---
> drivers/net/wireless/rt2x00/rt2400pci.c | 12 +++---
> drivers/net/wireless/rt2x00/rt2500pci.c | 12 +++---
> drivers/net/wireless/rt2x00/rt2800.h | 44 ++++++++++----------
> drivers/net/wireless/rt2x00/rt2800pci.c | 4 +-
> drivers/net/wireless/rt2x00/rt2x00queue.c | 18 ++++----
> drivers/net/wireless/rt2x00/rt2x00queue.h | 12 +++---
> drivers/net/wireless/rt2x00/rt2x00usb.c | 8 ++--
> drivers/net/wireless/rt2x00/rt61pci.c | 16 ++++----
> drivers/net/wireless/rt2x00/rt61pci.h | 62 ++++++++++++++--------------
> drivers/net/wireless/rt2x00/rt73usb.h | 36 ++++++++--------
> 10 files changed, 112 insertions(+), 112 deletions(-)
>
> diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
> index 2fc6ca5..54ca49a 100644
> --- a/drivers/net/wireless/rt2x00/rt2400pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2400pci.c
> @@ -664,12 +664,12 @@ static void rt2400pci_kick_queue(struct data_queue *queue)
> u32 reg;
>
> switch (queue->qid) {
> - case QID_AC_BE:
> + case QID_AC_VO:
> rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
> rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
> rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
> break;
> - case QID_AC_BK:
> + case QID_AC_VI:
> rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
> rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
> rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
> @@ -690,8 +690,8 @@ static void rt2400pci_stop_queue(struct data_queue *queue)
> u32 reg;
>
> switch (queue->qid) {
> - case QID_AC_BE:
> - case QID_AC_BK:
> + case QID_AC_VO:
> + case QID_AC_VI:
> case QID_ATIM:
> rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
> rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
> @@ -1322,13 +1322,13 @@ static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance)
> * 4 - Priority ring transmit done interrupt.
> */
> if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
> - rt2400pci_txdone(rt2x00dev, QID_AC_BE);
> + rt2400pci_txdone(rt2x00dev, QID_AC_VO);
>
> /*
> * 5 - Tx ring transmit done interrupt.
> */
> if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
> - rt2400pci_txdone(rt2x00dev, QID_AC_BK);
> + rt2400pci_txdone(rt2x00dev, QID_AC_VI);
>
> /* Enable interrupts again. */
> rt2x00dev->ops->lib->set_device_state(rt2x00dev,
> diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
> index d67f911..a9ff26a 100644
> --- a/drivers/net/wireless/rt2x00/rt2500pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2500pci.c
> @@ -754,12 +754,12 @@ static void rt2500pci_kick_queue(struct data_queue *queue)
> u32 reg;
>
> switch (queue->qid) {
> - case QID_AC_BE:
> + case QID_AC_VO:
> rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
> rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
> rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
> break;
> - case QID_AC_BK:
> + case QID_AC_VI:
> rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
> rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
> rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
> @@ -780,8 +780,8 @@ static void rt2500pci_stop_queue(struct data_queue *queue)
> u32 reg;
>
> switch (queue->qid) {
> - case QID_AC_BE:
> - case QID_AC_BK:
> + case QID_AC_VO:
> + case QID_AC_VI:
> case QID_ATIM:
> rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
> rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
> @@ -1455,13 +1455,13 @@ static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance)
> * 4 - Priority ring transmit done interrupt.
> */
> if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
> - rt2500pci_txdone(rt2x00dev, QID_AC_BE);
> + rt2500pci_txdone(rt2x00dev, QID_AC_VO);
>
> /*
> * 5 - Tx ring transmit done interrupt.
> */
> if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
> - rt2500pci_txdone(rt2x00dev, QID_AC_BK);
> + rt2500pci_txdone(rt2x00dev, QID_AC_VI);
>
> /* Enable interrupts again. */
> rt2x00dev->ops->lib->set_device_state(rt2x00dev,
> diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
> index 9ea0961..4c55e85 100644
> --- a/drivers/net/wireless/rt2x00/rt2800.h
> +++ b/drivers/net/wireless/rt2x00/rt2800.h
> @@ -213,10 +213,10 @@
>
> /*
> * WMM_AIFSN_CFG: Aifsn for each EDCA AC
> - * AIFSN0: AC_BE
> - * AIFSN1: AC_BK
> - * AIFSN2: AC_VI
> - * AIFSN3: AC_VO
> + * AIFSN0: AC_VO
> + * AIFSN1: AC_VI
> + * AIFSN2: AC_BE
> + * AIFSN3: AC_BK
> */
> #define WMM_AIFSN_CFG 0x0214
> #define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f)
> @@ -226,10 +226,10 @@
>
> /*
> * WMM_CWMIN_CSR: CWmin for each EDCA AC
> - * CWMIN0: AC_BE
> - * CWMIN1: AC_BK
> - * CWMIN2: AC_VI
> - * CWMIN3: AC_VO
> + * CWMIN0: AC_VO
> + * CWMIN1: AC_VI
> + * CWMIN2: AC_BE
> + * CWMIN3: AC_BK
> */
> #define WMM_CWMIN_CFG 0x0218
> #define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f)
> @@ -239,10 +239,10 @@
>
> /*
> * WMM_CWMAX_CSR: CWmax for each EDCA AC
> - * CWMAX0: AC_BE
> - * CWMAX1: AC_BK
> - * CWMAX2: AC_VI
> - * CWMAX3: AC_VO
> + * CWMAX0: AC_VO
> + * CWMAX1: AC_VI
> + * CWMAX2: AC_BE
> + * CWMAX3: AC_BK
> */
> #define WMM_CWMAX_CFG 0x021c
> #define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f)
> @@ -251,18 +251,18 @@
> #define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000)
>
> /*
> - * AC_TXOP0: AC_BK/AC_BE TXOP register
> - * AC0TXOP: AC_BK in unit of 32us
> - * AC1TXOP: AC_BE in unit of 32us
> + * AC_TXOP0: AC_VO/AC_VI TXOP register
> + * AC0TXOP: AC_VO in unit of 32us
> + * AC1TXOP: AC_VI in unit of 32us
> */
> #define WMM_TXOP0_CFG 0x0220
> #define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff)
> #define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000)
>
> /*
> - * AC_TXOP1: AC_VO/AC_VI TXOP register
> - * AC2TXOP: AC_VI in unit of 32us
> - * AC3TXOP: AC_VO in unit of 32us
> + * AC_TXOP1: AC_BE/AC_BK TXOP register
> + * AC2TXOP: AC_BE in unit of 32us
> + * AC3TXOP: AC_BK in unit of 32us
> */
> #define WMM_TXOP1_CFG 0x0224
> #define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff)
> @@ -288,7 +288,7 @@
> #define MCU_CMD_CFG 0x022c
>
> /*
> - * AC_BK register offsets
> + * AC_VO register offsets
> */
> #define TX_BASE_PTR0 0x0230
> #define TX_MAX_CNT0 0x0234
> @@ -296,7 +296,7 @@
> #define TX_DTX_IDX0 0x023c
>
> /*
> - * AC_BE register offsets
> + * AC_VI register offsets
> */
> #define TX_BASE_PTR1 0x0240
> #define TX_MAX_CNT1 0x0244
> @@ -304,7 +304,7 @@
> #define TX_DTX_IDX1 0x024c
>
> /*
> - * AC_VI register offsets
> + * AC_BE register offsets
> */
> #define TX_BASE_PTR2 0x0250
> #define TX_MAX_CNT2 0x0254
> @@ -312,7 +312,7 @@
> #define TX_DTX_IDX2 0x025c
>
> /*
> - * AC_VO register offsets
> + * AC_BK register offsets
> */
> #define TX_BASE_PTR3 0x0260
> #define TX_MAX_CNT3 0x0264
> diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
> index 195f0be3..403013f 100644
> --- a/drivers/net/wireless/rt2x00/rt2800pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2800pci.c
> @@ -217,10 +217,10 @@ static void rt2800pci_kick_queue(struct data_queue *queue)
> struct queue_entry *entry;
>
> switch (queue->qid) {
> + case QID_AC_VO:
> + case QID_AC_VI:
> case QID_AC_BE:
> case QID_AC_BK:
> - case QID_AC_VI:
> - case QID_AC_VO:
> entry = rt2x00queue_get_entry(queue, Q_INDEX);
> rt2800_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), entry->entry_idx);
> break;
> diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
> index 52cc92d..ca82b3a 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00queue.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
> @@ -746,10 +746,10 @@ void rt2x00queue_pause_queue(struct data_queue *queue)
> return;
>
> switch (queue->qid) {
> + case QID_AC_VO:
> + case QID_AC_VI:
> case QID_AC_BE:
> case QID_AC_BK:
> - case QID_AC_VI:
> - case QID_AC_VO:
> /*
> * For TX queues, we have to disable the queue
> * inside mac80211.
> @@ -770,10 +770,10 @@ void rt2x00queue_unpause_queue(struct data_queue *queue)
> return;
>
> switch (queue->qid) {
> + case QID_AC_VO:
> + case QID_AC_VI:
> case QID_AC_BE:
> case QID_AC_BK:
> - case QID_AC_VI:
> - case QID_AC_VO:
> /*
> * For TX queues, we have to enable the queue
> * inside mac80211.
> @@ -834,10 +834,10 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
> unsigned int i;
> bool started;
> bool tx_queue =
> - (queue->qid == QID_AC_BE) ||
> - (queue->qid == QID_AC_BK) ||
> + (queue->qid == QID_AC_VO) ||
> (queue->qid == QID_AC_VI) ||
> - (queue->qid == QID_AC_VO);
> + (queue->qid == QID_AC_BE) ||
> + (queue->qid == QID_AC_BK);
>
> mutex_lock(&queue->status_lock);
>
> @@ -1141,7 +1141,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
> /*
> * Initialize queue parameters.
> * RX: qid = QID_RX
> - * TX: qid = QID_AC_BE + index
> + * TX: qid = QID_AC_VO + index
> * TX: cw_min: 2^5 = 32.
> * TX: cw_max: 2^10 = 1024.
> * BCN: qid = QID_BEACON
> @@ -1149,7 +1149,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
> */
> rt2x00queue_init(rt2x00dev, rt2x00dev->rx, QID_RX);
>
> - qid = QID_AC_BE;
> + qid = QID_AC_VO;
> tx_queue_for_each(rt2x00dev, queue)
> rt2x00queue_init(rt2x00dev, queue, qid++);
>
> diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
> index 4765934..fab8e26 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00queue.h
> +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
> @@ -45,10 +45,10 @@
> /**
> * enum data_queue_qid: Queue identification
> *
> + * @QID_AC_VO: AC VO queue
> + * @QID_AC_VI: AC VI queue
> * @QID_AC_BE: AC BE queue
> * @QID_AC_BK: AC BK queue
> - * @QID_AC_VI: AC VI queue
> - * @QID_AC_VO: AC VO queue
> * @QID_HCCA: HCCA queue
> * @QID_MGMT: MGMT queue (prio queue)
> * @QID_RX: RX queue
> @@ -57,10 +57,10 @@
> * @QID_ATIM: Atim queue (value unspeficied, don't send it to device)
> */
> enum data_queue_qid {
> - QID_AC_BE = 0,
> - QID_AC_BK = 1,
> - QID_AC_VI = 2,
> - QID_AC_VO = 3,
> + QID_AC_VO = 0,
> + QID_AC_VI = 1,
> + QID_AC_BE = 2,
> + QID_AC_BK = 3,
> QID_HCCA = 4,
> QID_MGMT = 13,
> QID_RX = 14,
> diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
> index 8a16b51..1a9937d 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00usb.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
> @@ -353,10 +353,10 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
> void rt2x00usb_kick_queue(struct data_queue *queue)
> {
> switch (queue->qid) {
> + case QID_AC_VO:
> + case QID_AC_VI:
> case QID_AC_BE:
> case QID_AC_BK:
> - case QID_AC_VI:
> - case QID_AC_VO:
> if (!rt2x00queue_empty(queue))
> rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
> rt2x00usb_kick_tx_entry);
> @@ -403,10 +403,10 @@ void rt2x00usb_flush_queue(struct data_queue *queue)
> * Obtain the queue completion handler
> */
> switch (queue->qid) {
> + case QID_AC_VO:
> + case QID_AC_VI:
> case QID_AC_BE:
> case QID_AC_BK:
> - case QID_AC_VI:
> - case QID_AC_VO:
> completion = &queue->rt2x00dev->txdone_work;
> break;
> case QID_RX:
> diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
> index 7156b78..9405b10 100644
> --- a/drivers/net/wireless/rt2x00/rt61pci.c
> +++ b/drivers/net/wireless/rt2x00/rt61pci.c
> @@ -1171,22 +1171,22 @@ static void rt61pci_kick_queue(struct data_queue *queue)
> u32 reg;
>
> switch (queue->qid) {
> - case QID_AC_BE:
> + case QID_AC_VO:
> rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
> rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
> rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
> break;
> - case QID_AC_BK:
> + case QID_AC_VI:
> rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
> rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, 1);
> rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
> break;
> - case QID_AC_VI:
> + case QID_AC_BE:
> rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
> rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, 1);
> rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
> break;
> - case QID_AC_VO:
> + case QID_AC_BK:
> rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
> rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, 1);
> rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
> @@ -1202,22 +1202,22 @@ static void rt61pci_stop_queue(struct data_queue *queue)
> u32 reg;
>
> switch (queue->qid) {
> - case QID_AC_BE:
> + case QID_AC_VO:
> rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
> rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, 1);
> rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
> break;
> - case QID_AC_BK:
> + case QID_AC_VI:
> rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
> rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, 1);
> rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
> break;
> - case QID_AC_VI:
> + case QID_AC_BE:
> rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
> rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, 1);
> rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
> break;
> - case QID_AC_VO:
> + case QID_AC_BK:
> rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
> rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, 1);
> rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
> diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
> index afc803b..e3cd6db 100644
> --- a/drivers/net/wireless/rt2x00/rt61pci.h
> +++ b/drivers/net/wireless/rt2x00/rt61pci.h
> @@ -784,25 +784,25 @@ struct hw_pairwise_ta_entry {
> */
>
> /*
> - * AC0_BASE_CSR: AC_BK base address.
> + * AC0_BASE_CSR: AC_VO base address.
> */
> #define AC0_BASE_CSR 0x3400
> #define AC0_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
>
> /*
> - * AC1_BASE_CSR: AC_BE base address.
> + * AC1_BASE_CSR: AC_VI base address.
> */
> #define AC1_BASE_CSR 0x3404
> #define AC1_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
>
> /*
> - * AC2_BASE_CSR: AC_VI base address.
> + * AC2_BASE_CSR: AC_BE base address.
> */
> #define AC2_BASE_CSR 0x3408
> #define AC2_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
>
> /*
> - * AC3_BASE_CSR: AC_VO base address.
> + * AC3_BASE_CSR: AC_BK base address.
> */
> #define AC3_BASE_CSR 0x340c
> #define AC3_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
> @@ -814,7 +814,7 @@ struct hw_pairwise_ta_entry {
> #define MGMT_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
>
> /*
> - * TX_RING_CSR0: TX Ring size for AC_BK, AC_BE, AC_VI, AC_VO.
> + * TX_RING_CSR0: TX Ring size for AC_VO, AC_VI, AC_BE, AC_BK.
> */
> #define TX_RING_CSR0 0x3418
> #define TX_RING_CSR0_AC0_RING_SIZE FIELD32(0x000000ff)
> @@ -833,10 +833,10 @@ struct hw_pairwise_ta_entry {
>
> /*
> * AIFSN_CSR: AIFSN for each EDCA AC.
> - * AIFSN0: For AC_BK.
> - * AIFSN1: For AC_BE.
> - * AIFSN2: For AC_VI.
> - * AIFSN3: For AC_VO.
> + * AIFSN0: For AC_VO.
> + * AIFSN1: For AC_VI.
> + * AIFSN2: For AC_BE.
> + * AIFSN3: For AC_BK.
> */
> #define AIFSN_CSR 0x3420
> #define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
> @@ -846,10 +846,10 @@ struct hw_pairwise_ta_entry {
>
> /*
> * CWMIN_CSR: CWmin for each EDCA AC.
> - * CWMIN0: For AC_BK.
> - * CWMIN1: For AC_BE.
> - * CWMIN2: For AC_VI.
> - * CWMIN3: For AC_VO.
> + * CWMIN0: For AC_VO.
> + * CWMIN1: For AC_VI.
> + * CWMIN2: For AC_BE.
> + * CWMIN3: For AC_BK.
> */
> #define CWMIN_CSR 0x3424
> #define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
> @@ -859,10 +859,10 @@ struct hw_pairwise_ta_entry {
>
> /*
> * CWMAX_CSR: CWmax for each EDCA AC.
> - * CWMAX0: For AC_BK.
> - * CWMAX1: For AC_BE.
> - * CWMAX2: For AC_VI.
> - * CWMAX3: For AC_VO.
> + * CWMAX0: For AC_VO.
> + * CWMAX1: For AC_VI.
> + * CWMAX2: For AC_BE.
> + * CWMAX3: For AC_BK.
> */
> #define CWMAX_CSR 0x3428
> #define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
> @@ -883,14 +883,14 @@ struct hw_pairwise_ta_entry {
>
> /*
> * TX_CNTL_CSR: KICK/Abort TX.
> - * KICK_TX_AC0: For AC_BK.
> - * KICK_TX_AC1: For AC_BE.
> - * KICK_TX_AC2: For AC_VI.
> - * KICK_TX_AC3: For AC_VO.
> - * ABORT_TX_AC0: For AC_BK.
> - * ABORT_TX_AC1: For AC_BE.
> - * ABORT_TX_AC2: For AC_VI.
> - * ABORT_TX_AC3: For AC_VO.
> + * KICK_TX_AC0: For AC_VO.
> + * KICK_TX_AC1: For AC_VI.
> + * KICK_TX_AC2: For AC_BE.
> + * KICK_TX_AC3: For AC_BK.
> + * ABORT_TX_AC0: For AC_VO.
> + * ABORT_TX_AC1: For AC_VI.
> + * ABORT_TX_AC2: For AC_BE.
> + * ABORT_TX_AC3: For AC_BK.
> */
> #define TX_CNTL_CSR 0x3430
> #define TX_CNTL_CSR_KICK_TX_AC0 FIELD32(0x00000001)
> @@ -1010,18 +1010,18 @@ struct hw_pairwise_ta_entry {
> #define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040)
>
> /*
> - * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
> - * AC0_TX_OP: For AC_BK, in unit of 32us.
> - * AC1_TX_OP: For AC_BE, in unit of 32us.
> + * AC_TXOP_CSR0: AC_VO/AC_VI TXOP register.
> + * AC0_TX_OP: For AC_VO, in unit of 32us.
> + * AC1_TX_OP: For AC_VI, in unit of 32us.
> */
> #define AC_TXOP_CSR0 0x3474
> #define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff)
> #define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000)
>
> /*
> - * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
> - * AC2_TX_OP: For AC_VI, in unit of 32us.
> - * AC3_TX_OP: For AC_VO, in unit of 32us.
> + * AC_TXOP_CSR1: AC_BE/AC_BK TXOP register.
> + * AC2_TX_OP: For AC_BE, in unit of 32us.
> + * AC3_TX_OP: For AC_BK, in unit of 32us.
> */
> #define AC_TXOP_CSR1 0x3478
> #define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)
> diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
> index 1315ce5..9f6b470 100644
> --- a/drivers/net/wireless/rt2x00/rt73usb.h
> +++ b/drivers/net/wireless/rt2x00/rt73usb.h
> @@ -689,10 +689,10 @@ struct hw_pairwise_ta_entry {
>
> /*
> * AIFSN_CSR: AIFSN for each EDCA AC.
> - * AIFSN0: For AC_BK.
> - * AIFSN1: For AC_BE.
> - * AIFSN2: For AC_VI.
> - * AIFSN3: For AC_VO.
> + * AIFSN0: For AC_VO.
> + * AIFSN1: For AC_VI.
> + * AIFSN2: For AC_BE.
> + * AIFSN3: For AC_BK.
> */
> #define AIFSN_CSR 0x0400
> #define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
> @@ -702,10 +702,10 @@ struct hw_pairwise_ta_entry {
>
> /*
> * CWMIN_CSR: CWmin for each EDCA AC.
> - * CWMIN0: For AC_BK.
> - * CWMIN1: For AC_BE.
> - * CWMIN2: For AC_VI.
> - * CWMIN3: For AC_VO.
> + * CWMIN0: For AC_VO.
> + * CWMIN1: For AC_VI.
> + * CWMIN2: For AC_BE.
> + * CWMIN3: For AC_BK.
> */
> #define CWMIN_CSR 0x0404
> #define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
> @@ -715,10 +715,10 @@ struct hw_pairwise_ta_entry {
>
> /*
> * CWMAX_CSR: CWmax for each EDCA AC.
> - * CWMAX0: For AC_BK.
> - * CWMAX1: For AC_BE.
> - * CWMAX2: For AC_VI.
> - * CWMAX3: For AC_VO.
> + * CWMAX0: For AC_VO.
> + * CWMAX1: For AC_VI.
> + * CWMAX2: For AC_BE.
> + * CWMAX3: For AC_BK.
> */
> #define CWMAX_CSR 0x0408
> #define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
> @@ -727,18 +727,18 @@ struct hw_pairwise_ta_entry {
> #define CWMAX_CSR_CWMAX3 FIELD32(0x0000f000)
>
> /*
> - * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
> - * AC0_TX_OP: For AC_BK, in unit of 32us.
> - * AC1_TX_OP: For AC_BE, in unit of 32us.
> + * AC_TXOP_CSR0: AC_VO/AC_VI TXOP register.
> + * AC0_TX_OP: For AC_VO, in unit of 32us.
> + * AC1_TX_OP: For AC_VI, in unit of 32us.
> */
> #define AC_TXOP_CSR0 0x040c
> #define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff)
> #define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000)
>
> /*
> - * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
> - * AC2_TX_OP: For AC_VI, in unit of 32us.
> - * AC3_TX_OP: For AC_VO, in unit of 32us.
> + * AC_TXOP_CSR1: AC_BE/AC_BK TXOP register.
> + * AC2_TX_OP: For AC_BE, in unit of 32us.
> + * AC3_TX_OP: For AC_BK, in unit of 32us.
> */
> #define AC_TXOP_CSR1 0x0410
> #define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)
>


2010-12-13 11:40:11

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use

From: Johannes Stezenbach <[email protected]>

When an rt2x00 USB device is unplugged while in use, it reliably
hangs the whole system. After some time the watchdog prints:

BUG: soft lockup - CPU#0 stuck for 64s! [kworker/u:0:5]
...
[<c01a88d8>] (usb_submit_urb+0x0/0x2ac) from [<bf0e752c>] (rt2x00usb_kick_rx_entry+0xb4/0xe8 [rt2x00usb])
[<bf0e7478>] (rt2x00usb_kick_rx_entry+0x0/0xe8 [rt2x00usb]) from [<bf0e7588>] (rt2x00usb_clear_entry+x28/0x2c [rt2x00usb])
[<bf0e7560>] (rt2x00usb_clear_entry+0x0/0x2c [rt2x00usb]) from [<bf0d5bc4>] (rt2x00lib_rxdone+0x2e0/0x2f8 [rt2x00lib])
[<bf0d58e4>] (rt2x00lib_rxdone+0x0/0x2f8 [rt2x00lib]) from [<bf0e7e00>] (rt2x00usb_work_rxdone+0x54/0x74 [rt2x00usb])
[<bf0e7dac>] (rt2x00usb_work_rxdone+0x0/0x74 [rt2x00usb]) from [<c00542b4>] (process_one_work+0x20c/0x35c)

Clear the DEVICE_STATE_PRESENT flag when usb_submit_urb()
returns -ENODEV to fix this.

Signed-off-by: Johannes Stezenbach <[email protected]>
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00usb.c | 14 ++++++++++++--
1 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 9ac1459..3a6c83e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -235,6 +235,7 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
u32 length;
+ int status;

if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
return;
@@ -251,7 +252,10 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
entry->skb->data, length,
rt2x00usb_interrupt_txdone, entry);

- if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) {
+ status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+ if (status) {
+ if (status == -ENODEV)
+ clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
}
@@ -435,6 +439,7 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
to_usb_device_intf(entry->queue->rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
int pipe;
+ int status;

entry->flags = 0;

@@ -445,7 +450,12 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
rt2x00usb_interrupt_rxdone, entry);

set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) {
+
+ status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+ if (status) {
+ if (status == -ENODEV)
+ clear_bit(DEVICE_STATE_PRESENT,
+ &entry->queue->rt2x00dev->flags);
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
}
--
1.7.2.3


2010-12-13 13:16:39

by Walter Goldens

[permalink] [raw]
Subject: Re: [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use

>
> It should be possible, but what are the exact problems that
> you encounter?
> Is there a difference between going from rt3070sta to
> rt2800usb and vice versa?
> (Please note that the rt2x00 project doesn't maintain the
> rt3070sta
> driver in the staging directory).
Thanks for replying.

I hope these sets of patches ameliorate all of the unplugging and rmmod'ing for the rt2800usb/rt3070.

And yes, I know the rt2x00 project does not cover staging drivers, actually the staging driver adopted by Ubuntu (and others) is in fact rt2870sta and not the rt3070sta (from Ralink), but they both do not allow switching between them and rt2800usb.
On my system, when rt3070sta is loaded first and then subsequently rmmod'ed to modprobe the rt2800usb the following error occurs:

[14775.401131] cfg80211: 2474000 KHz - 2494000 KHz @ KHz), (300 mBi, 2000 mBm)
[14775.413682] ieee80211 phy0: Selected rate control algorithm 'minstrel_ht'
[14775.418857] Registered led device: rt2800usb-phy0::radio
[14775.421376] Registered led device: rt2800usb-phy0::assoc
[14775.423420] Registered led device: rt2800usb-phy0::quality
[14775.426517] usbcore: registered new interface driver rt2800usb
[14775.449012] udev[4470]: renamed network interface wlan0 to wlan2
[14776.031493] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x3240 with error -71.
[14776.605073] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x7014 with error -71.
[14777.173373] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x701c with error -71.
[14777.748941] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x01 failed for offset 0x0000 with error -71.
[14777.748956] phy0 -> rt2800usb_write_firmware: Error - Failed to write Firmware to device.
[14778.307770] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x07 failed for offset 0x0400 with error -71.
[14778.876970] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x07 failed for offset 0x0400 with error -71.

then the system freezes, partially, meaning for example I cannot issue simple "ifconfig" - this command as well as other commands are inactive. To unlock the system, thus command prompt and so on I have to unplug the device, then dmesg basically is flooding with errors.

LOG:
[15254.800224] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x6640 with error -71.
[15255.365301] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x1e48 with error -71.
[15255.939468] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x6b24 with error -71.
[15256.507077] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x6648 with error -71.
[15257.078835] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x1e50 with error -71.
[15257.650201] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x6b28 with error -71.
[15258.216303] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x6650 with error -71.
[15258.782110] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x1e58 with error -71.
[15259.131561] usb 5-2.6: USB disconnect, address 6
[15259.131791] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x06 failed for offset 0x6b2c with error -19.
[15259.151361] phy0 -> rt2800_wait_bbp_ready: Error - BBP register access failed, aborting.
[15259.151379] phy0 -> rt2800usb_set_device_state: Error - Device failed to enter state 4 (-5).

Now trying vice versa rt2800usb --> rt3070sta:
Interestingly, when rt2800usb is first loaded and then rmmod'ed without unplugging followed by loading of the rt3070sta takes about a minute or so, but the rt3070sta becomes operational. But not always. A repeat of the procedure partially froze the system again.

Tried with both staging rt2870sta and manually compiled rt3070sta - the result is the same, total or partial system failure, forcing me to plug/unplug the USB chip.

Walter




2010-12-13 11:40:37

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 16/17] rt2x00: Pad beacon to multiple of 32 bits.

From: Wolfgang Kufner <[email protected]>

Pad beacon to a multiple of 32 bits in preparation for the change
from memcpy_toio() to __iowrite32_copy() in register_multiwrite().

Signed-off-by: Wolfgang Kufner <[email protected]>
Acked-by: Helmut Schaa <[email protected]>
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2800lib.c | 9 ++++++---
drivers/net/wireless/rt2x00/rt61pci.c | 8 ++++++--
drivers/net/wireless/rt2x00/rt73usb.c | 9 ++++++---
3 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index b7de1a5..54917a2 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -772,6 +772,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
unsigned int beacon_base;
+ unsigned int padding_len;
u32 reg;

/*
@@ -806,11 +807,13 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);

/*
- * Write entire beacon with TXWI to register.
+ * Write entire beacon with TXWI and padding to register.
*/
+ padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
+ skb_pad(entry->skb, padding_len);
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2800_register_multiwrite(rt2x00dev, beacon_base,
- entry->skb->data, entry->skb->len);
+ rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
+ entry->skb->len + padding_len);

/*
* Enable beaconing again.
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 9405b10..8de44dd 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1961,6 +1961,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
unsigned int beacon_base;
+ unsigned int padding_len;
u32 reg;

/*
@@ -1982,13 +1983,16 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);

/*
- * Write entire beacon with descriptor to register.
+ * Write entire beacon with descriptor and padding to register.
*/
+ padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
+ skb_pad(entry->skb, padding_len);
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
entry_priv->desc, TXINFO_SIZE);
rt2x00pci_register_multiwrite(rt2x00dev, beacon_base + TXINFO_SIZE,
- entry->skb->data, entry->skb->len);
+ entry->skb->data,
+ entry->skb->len + padding_len);

/*
* Enable beaconing again.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 0b3959b..0b4e859 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1546,6 +1546,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
unsigned int beacon_base;
+ unsigned int padding_len;
u32 reg;

/*
@@ -1573,11 +1574,13 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);

/*
- * Write entire beacon with descriptor to register.
+ * Write entire beacon with descriptor and padding to register.
*/
+ padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
+ skb_pad(entry->skb, padding_len);
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2x00usb_register_multiwrite(rt2x00dev, beacon_base,
- entry->skb->data, entry->skb->len);
+ rt2x00usb_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
+ entry->skb->len + padding_len);

/*
* Enable beaconing again.
--
1.7.2.3


2010-12-13 11:40:35

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 15/17] rt2x00: remove stray semicolon

From: Johannes Stezenbach <[email protected]>

The stray semicolon after DEBUG_PRINTK_MSG causes things
like "if (...) WARNING(...); else {}" to fail with syntax error.

Signed-off-by: Johannes Stezenbach <[email protected]>
Acked-by: Gertjan van Wingerde <[email protected]>
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 556b744..5ea62554 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -66,7 +66,7 @@

#ifdef CONFIG_RT2X00_DEBUG
#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \
- DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, ##__args);
+ DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, ##__args)
#else
#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \
do { } while (0)
--
1.7.2.3


2010-12-13 11:40:39

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 17/17] rt2x00: Fix firmware loading regression on x86_64.

From: Wolfgang Kufner <[email protected]>

Commit 6175ddf06b6172046a329e3abfd9c901a43efd2e changes the way
memcpy_toio() works for x86_64, causing firmware loading to fail for
some Ralink WLAN devices with the rt2800pci driver since linux 2.6.34.
This causes the log message: "phy0 -> rt2800pci_load_firmware: Error -
PBF system register not ready.".

Fix this by using __iowrite32_copy instead of memcpy_toio().

Signed-off-by: Wolfgang Kufner <[email protected]>
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00pci.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index b854d62..746ce8f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -64,7 +64,7 @@ static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
const void *value,
const u32 length)
{
- memcpy_toio(rt2x00dev->csr.base + offset, value, length);
+ __iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2);
}

/**
--
1.7.2.3


2010-12-16 20:43:30

by Ivo Van Doorn

[permalink] [raw]
Subject: Re: [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use

Hi,

> Even with the latest patches, rmmod'ing the rt2xXXX stuff causes a complete system freeze. Unless I bring down the interface first via 'ifconfig wlanX down', unloading the driver while operational equates OS hang and hard reset.

Odd I have been testing this while stresstesting the card, and either
unplugging, rmmod or ifdown, and I couldn't
reproduce any crashes. Has the stacktrace changed after these patches?

Ivo

2010-12-13 11:40:22

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 08/17] rt2x00: Introduce 3 queue commands in drivers (start, kick, stop).

As part of the queue refactoring, we now introduce
3 queue commands: start, kick, stop.

- Start: will enable a queue, for TX this will
not mean anything, while for beacons and RX
this will update the registers to enable the queue.
- Kick: This will kick all pending frames to
the hardware. This is needed for the TX queue
to push all frames to the HW after the queue
has been started
- Stop: This will stop the queue in the hardware,
and cancel any pending work (So this doesn't
mean the queue is empty after a stop!).

Move all code from the drivers into the appropriate
functions, and link those calls to the old rt2x00lib
callback functions (we will fix this later when we
refactor the queue control inside rt2x00lib).

Signed-off-by: Ivo van Doorn <[email protected]>
Acked-by: Helmut Schaa <[email protected]>
---
drivers/net/wireless/rt2x00/rt2400pci.c | 131 +++++++++++++++++---------
drivers/net/wireless/rt2x00/rt2500pci.c | 131 +++++++++++++++++---------
drivers/net/wireless/rt2x00/rt2500usb.c | 84 +++++++++++------
drivers/net/wireless/rt2x00/rt2800pci.c | 129 +++++++++++++++-----------
drivers/net/wireless/rt2x00/rt2800usb.c | 84 +++++++++++------
drivers/net/wireless/rt2x00/rt2x00usb.c | 12 +-
drivers/net/wireless/rt2x00/rt2x00usb.h | 8 +-
drivers/net/wireless/rt2x00/rt61pci.c | 154 +++++++++++++++++++++----------
drivers/net/wireless/rt2x00/rt73usb.c | 84 +++++++++++------
9 files changed, 530 insertions(+), 287 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 6278660..35d9a06 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -633,6 +633,88 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev,
}

/*
+ * Queue handlers.
+ */
+static void rt2400pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 0);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2400pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_BE:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_AC_BK:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2400pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_BE:
+ case QID_AC_BK:
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Initialization functions.
*/
static bool rt2400pci_get_entry_state(struct queue_entry *entry)
@@ -878,17 +960,6 @@ static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
- rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF));
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-}
-
static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -988,8 +1059,10 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2400pci_disable_radio(rt2x00dev);
break;
case STATE_RADIO_RX_ON:
+ rt2400pci_start_queue(rt2x00dev->rx);
+ break;
case STATE_RADIO_RX_OFF:
- rt2400pci_toggle_rx(rt2x00dev, state);
+ rt2400pci_stop_queue(rt2x00dev->rx);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
@@ -1122,36 +1195,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}

-static void rt2400pci_kick_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
-}
-
-static void rt2400pci_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
- rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
- rt2x00_set_field32(&reg, CSR14_TBCN, 0);
- rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
- } else {
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
- }
-}
-
/*
* RX control handlers
*/
@@ -1631,8 +1674,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.link_tuner = rt2400pci_link_tuner,
.write_tx_desc = rt2400pci_write_tx_desc,
.write_beacon = rt2400pci_write_beacon,
- .kick_tx_queue = rt2400pci_kick_tx_queue,
- .kill_tx_queue = rt2400pci_kill_tx_queue,
+ .kick_tx_queue = rt2400pci_kick_queue,
+ .kill_tx_queue = rt2400pci_stop_queue,
.fill_rxdone = rt2400pci_fill_rxdone,
.config_filter = rt2400pci_config_filter,
.config_intf = rt2400pci_config_intf,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index ce9212f..bee7ce1 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -723,6 +723,88 @@ dynamic_cca_tune:
}

/*
+ * Queue handlers.
+ */
+static void rt2500pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 0);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2500pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_BE:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_AC_BK:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2500pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_BE:
+ case QID_AC_BK:
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Initialization functions.
*/
static bool rt2500pci_get_entry_state(struct queue_entry *entry)
@@ -1033,17 +1115,6 @@ static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
- rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF));
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-}
-
static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -1143,8 +1214,10 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2500pci_disable_radio(rt2x00dev);
break;
case STATE_RADIO_RX_ON:
+ rt2500pci_start_queue(rt2x00dev->rx);
+ break;
case STATE_RADIO_RX_OFF:
- rt2500pci_toggle_rx(rt2x00dev, state);
+ rt2500pci_stop_queue(rt2x00dev->rx);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
@@ -1276,36 +1349,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}

-static void rt2500pci_kick_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
-}
-
-static void rt2500pci_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
- rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
- rt2x00_set_field32(&reg, CSR14_TBCN, 0);
- rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
- } else {
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
- }
-}
-
/*
* RX control handlers
*/
@@ -1928,8 +1971,8 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.link_tuner = rt2500pci_link_tuner,
.write_tx_desc = rt2500pci_write_tx_desc,
.write_beacon = rt2500pci_write_beacon,
- .kick_tx_queue = rt2500pci_kick_tx_queue,
- .kill_tx_queue = rt2500pci_kill_tx_queue,
+ .kick_tx_queue = rt2500pci_kick_queue,
+ .kill_tx_queue = rt2500pci_stop_queue,
.fill_rxdone = rt2500pci_fill_rxdone,
.config_filter = rt2500pci_config_filter,
.config_intf = rt2500pci_config_intf,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index bbfa671..52bd0ed 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -739,6 +739,57 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev,
}

/*
+ * Queue handlers.
+ */
+static void rt2500usb_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u16 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+ break;
+ case QID_BEACON:
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2500usb_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u16 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+ break;
+ case QID_BEACON:
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ break;
+ default:
+ break;
+ }
+
+ rt2x00usb_stop_queue(queue);
+}
+
+/*
* Initialization functions.
*/
static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
@@ -931,17 +982,6 @@ static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt2500usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u16 reg;
-
- rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
- rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF));
- rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
-}
-
static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev)
{
/*
@@ -1018,8 +1058,10 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2500usb_disable_radio(rt2x00dev);
break;
case STATE_RADIO_RX_ON:
+ rt2500usb_start_queue(rt2x00dev->rx);
+ break;
case STATE_RADIO_RX_OFF:
- rt2500usb_toggle_rx(rt2x00dev, state);
+ rt2500usb_stop_queue(rt2x00dev->rx);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
@@ -1203,22 +1245,6 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
return length;
}

-static void rt2500usb_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u16 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
- rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
- rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
- rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
- rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
- }
-
- rt2x00usb_kill_tx_queue(queue);
-}
-
/*
* RX control handlers
*/
@@ -1823,7 +1849,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.write_beacon = rt2500usb_write_beacon,
.get_tx_data_len = rt2500usb_get_tx_data_len,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt2500usb_kill_tx_queue,
+ .kill_tx_queue = rt2500usb_stop_queue,
.fill_rxdone = rt2500usb_fill_rxdone,
.config_shared_key = rt2500usb_config_key,
.config_pairwise_key = rt2500usb_config_key,
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 2b68009..08b55b5 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -186,6 +186,77 @@ static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
#endif /* CONFIG_PCI */

/*
+ * Queue handlers.
+ */
+static void rt2800pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ };
+}
+
+static void rt2800pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ struct queue_entry *entry;
+
+ switch (queue->qid) {
+ case QID_AC_BE:
+ case QID_AC_BK:
+ case QID_AC_VI:
+ case QID_AC_VO:
+ entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ rt2800_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), entry->entry_idx);
+ break;
+ case QID_MGMT:
+ entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ rt2800_register_write(rt2x00dev, TX_CTX_IDX(5), entry->entry_idx);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2800pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Firmware functions
*/
static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -323,17 +394,6 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX,
- (state == STATE_RADIO_RX_ON));
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-}
-
static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -478,8 +538,10 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800pci_set_state(rt2x00dev, STATE_SLEEP);
break;
case STATE_RADIO_RX_ON:
+ rt2800pci_start_queue(rt2x00dev->rx);
+ break;
case STATE_RADIO_RX_OFF:
- rt2800pci_toggle_rx(rt2x00dev, state);
+ rt2800pci_stop_queue(rt2x00dev->rx);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
@@ -566,45 +628,6 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry,
}

/*
- * TX data initialization
- */
-static void rt2800pci_kick_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
- unsigned int qidx;
-
- if (queue->qid == QID_MGMT)
- qidx = 5;
- else
- qidx = queue->qid;
-
- rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), entry->entry_idx);
-}
-
-static void rt2800pci_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
- return;
- }
-
- rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, (queue->qid == QID_AC_VI));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, (queue->qid == QID_AC_VO));
- rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
-}
-
-/*
* RX control handlers
*/
static void rt2800pci_fill_rxdone(struct queue_entry *entry,
@@ -983,8 +1006,8 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.write_tx_desc = rt2800pci_write_tx_desc,
.write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
- .kick_tx_queue = rt2800pci_kick_tx_queue,
- .kill_tx_queue = rt2800pci_kill_tx_queue,
+ .kick_tx_queue = rt2800pci_kick_queue,
+ .kill_tx_queue = rt2800pci_stop_queue,
.fill_rxdone = rt2800pci_fill_rxdone,
.config_shared_key = rt2800_config_shared_key,
.config_pairwise_key = rt2800_config_pairwise_key,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 1dfa59d..ee51936 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -50,6 +50,57 @@ module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");

/*
+ * Queue handlers.
+ */
+static void rt2800usb_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2800usb_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ }
+
+ rt2x00usb_stop_queue(queue);
+}
+
+/*
* Firmware functions
*/
static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -107,17 +158,6 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
/*
* Device state switch handlers.
*/
-static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX,
- (state == STATE_RADIO_RX_ON));
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-}
-
static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -215,8 +255,10 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800usb_set_state(rt2x00dev, STATE_SLEEP);
break;
case STATE_RADIO_RX_ON:
+ rt2800usb_start_queue(rt2x00dev->rx);
+ break;
case STATE_RADIO_RX_OFF:
- rt2800usb_toggle_rx(rt2x00dev, state);
+ rt2800usb_stop_queue(rt2x00dev->rx);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
@@ -389,22 +431,6 @@ static void rt2800usb_work_txdone(struct work_struct *work)
}
}

-static void rt2800usb_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
- }
-
- rt2x00usb_kill_tx_queue(queue);
-}
-
/*
* RX control handlers
*/
@@ -605,7 +631,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.write_beacon = rt2800_write_beacon,
.get_tx_data_len = rt2800usb_get_tx_data_len,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt2800usb_kill_tx_queue,
+ .kill_tx_queue = rt2800usb_stop_queue,
.fill_rxdone = rt2800usb_fill_rxdone,
.config_shared_key = rt2800_config_shared_key,
.config_pairwise_key = rt2800_config_pairwise_key,
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 608200e..12958a4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -268,7 +268,7 @@ void rt2x00usb_kick_tx_queue(struct data_queue *queue)
}
EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);

-static void rt2x00usb_kill_tx_entry(struct queue_entry *entry)
+static void rt2x00usb_kill_entry(struct queue_entry *entry)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
@@ -287,12 +287,12 @@ static void rt2x00usb_kill_tx_entry(struct queue_entry *entry)
usb_kill_urb(bcn_priv->guardian_urb);
}

-void rt2x00usb_kill_tx_queue(struct data_queue *queue)
+void rt2x00usb_stop_queue(struct data_queue *queue)
{
rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
- rt2x00usb_kill_tx_entry);
+ rt2x00usb_kill_entry);
}
-EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
+EXPORT_SYMBOL_GPL(rt2x00usb_stop_queue);

static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
{
@@ -316,7 +316,7 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
* Kill all entries in the queue, afterwards we need to
* wait a bit for all URBs to be cancelled.
*/
- rt2x00usb_kill_tx_queue(queue);
+ rt2x00usb_stop_queue(queue);

/*
* In case that a driver has overriden the txdone_work
@@ -423,7 +423,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
REGISTER_TIMEOUT);

/*
- * The USB version of kill_tx_queue also works
+ * The USB version of also works
* on the RX queue.
*/
rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev->rx);
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index c2d997f..656a35f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -387,13 +387,13 @@ struct queue_entry_priv_usb_bcn {
void rt2x00usb_kick_tx_queue(struct data_queue *queue);

/**
- * rt2x00usb_kill_tx_queue - Kill data queue
- * @queue: Data queue to kill
+ * rt2x00usb_stop_queue - Stop data queue
+ * @queue: Data queue to stop
*
* This will walk through all entries of the queue and kill all
- * previously kicked frames before they can be send.
+ * URB's which were send to the device.
*/
-void rt2x00usb_kill_tx_queue(struct data_queue *queue);
+void rt2x00usb_stop_queue(struct data_queue *queue);

/**
* rt2x00usb_watchdog - Watchdog for USB communication
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 6ad0c1c..044f500 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1140,6 +1140,106 @@ dynamic_cca_tune:
}

/*
+ * Queue handlers.
+ */
+static void rt61pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt61pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_BE:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_BK:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_VI:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_VO:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt61pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_BE:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_BK:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_VI:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_VO:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Firmware functions
*/
static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -1616,17 +1716,6 @@ static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF));
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
-}
-
static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -1744,8 +1833,10 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt61pci_disable_radio(rt2x00dev);
break;
case STATE_RADIO_RX_ON:
+ rt61pci_start_queue(rt2x00dev->rx);
+ break;
case STATE_RADIO_RX_OFF:
- rt61pci_toggle_rx(rt2x00dev, state);
+ rt61pci_stop_queue(rt2x00dev->rx);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
@@ -1925,41 +2016,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
entry->skb = NULL;
}

-static void rt61pci_kick_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, (queue->qid == QID_AC_VI));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, (queue->qid == QID_AC_VO));
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
-}
-
-static void rt61pci_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
- rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
- rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
- return;
- }
-
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, (queue->qid == QID_AC_VI));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, (queue->qid == QID_AC_VO));
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
-}
-
/*
* RX control handlers
*/
@@ -2846,8 +2902,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.link_tuner = rt61pci_link_tuner,
.write_tx_desc = rt61pci_write_tx_desc,
.write_beacon = rt61pci_write_beacon,
- .kick_tx_queue = rt61pci_kick_tx_queue,
- .kill_tx_queue = rt61pci_kill_tx_queue,
+ .kick_tx_queue = rt61pci_kick_queue,
+ .kill_tx_queue = rt61pci_stop_queue,
.fill_rxdone = rt61pci_fill_rxdone,
.config_shared_key = rt61pci_config_shared_key,
.config_pairwise_key = rt61pci_config_pairwise_key,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 3934dad..e9b1e3d 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1031,6 +1031,57 @@ dynamic_cca_tune:
}

/*
+ * Queue handlers.
+ */
+static void rt73usb_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt73usb_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+
+ rt2x00usb_stop_queue(queue);
+}
+
+/*
* Firmware functions
*/
static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -1324,17 +1375,6 @@ static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF));
- rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
-}
-
static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
{
/*
@@ -1402,8 +1442,10 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt73usb_disable_radio(rt2x00dev);
break;
case STATE_RADIO_RX_ON:
+ rt73usb_start_queue(rt2x00dev->rx);
+ break;
case STATE_RADIO_RX_OFF:
- rt73usb_toggle_rx(rt2x00dev, state);
+ rt73usb_stop_queue(rt2x00dev->rx);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
@@ -1579,22 +1621,6 @@ static int rt73usb_get_tx_data_len(struct queue_entry *entry)
return length;
}

-static void rt73usb_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
- rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
- rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
- rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
- }
-
- rt2x00usb_kill_tx_queue(queue);
-}
-
/*
* RX control handlers
*/
@@ -2290,7 +2316,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.write_beacon = rt73usb_write_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
- .kill_tx_queue = rt73usb_kill_tx_queue,
+ .kill_tx_queue = rt73usb_stop_queue,
.fill_rxdone = rt73usb_fill_rxdone,
.config_shared_key = rt73usb_config_shared_key,
.config_pairwise_key = rt73usb_config_pairwise_key,
--
1.7.2.3


2010-12-14 18:44:36

by Ivo Van Doorn

[permalink] [raw]
Subject: Re: [PATCH 14/17] rt2x00: Fix WMM Queue naming

Hi,

>> The Queue names were incorrectly copied from the legacy drivers,
>> as a result the queue names were inversed to what was expected.
>>
>> This renames the queues using this mapping:
>> ? ? ? QID_AC_BK -> QID_AC_VO (priority 0)
>> ? ? ? QID_AC_BE -> QID_AC_VI (priority 1)
>> ? ? ? QID_AC_VI -> QID_AC_BE (priority 2)
>> ? ? ? QID_AC_VO -> QID_AC_BK (priority 3)
>>
>> Note that this was a naming problem only, which didn't affect
>> the assignment of frames to their respective queues.
>>
>> Signed-off-by: Ivo van Doorn <[email protected]>
>
> Ivo, due to the latest info from Ralink I'd say we should drop this patch
> and instead introduce a mac80211_to_rt2x00_qid mapper that maps from
> ieee80211_ac_numbers to data_queue_qid.
>
> This patch doesn't cause any harm, but we would have to revert it partly
> if we introduce the queue mapping as needed by the rt2x00 devices.

I don't agree, this patch can safely be applied, since the mapping
is in the endpoint assignment, rather the register value usage,
I think the more optimal solution is fixing rt2x00usb_assign_endpoints.
In there it currently assigns endpoints assuming the first endpoint
is the highest priority, while we should be able to simply swap that
to invert the logic.

Ivo

2010-12-13 11:40:15

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 05/17] rt2x00: Ensure TX-ed frames are returned in the original state.

From: Gertjan van Wingerde <[email protected]>

Recent changes to the TX-done code of rt2x00 resulted in TX-ed frames not
being returned to mac80211 in the original state, and therefore with
insufficient headroom for re-transmissions.

Fix this by reverting the changes done and by ensuring we remove the inserted
L2pad by moving the header backwards instead of the data forwards.

At the same time also make sure that the rt2x00queue_remove_l2pad will not
move any memory when a frame has no data at all.

Signed-off-by: Gertjan van Wingerde <[email protected]>
Acked-by: Helmut Schaa <[email protected]>
Cc: Jay Hung <[email protected]>
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00queue.c | 13 ++++++++-----
1 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index a3d79c7..35133d8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -199,15 +199,18 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)

void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
{
- unsigned int l2pad = L2PAD_SIZE(header_length);
+ /*
+ * L2 padding is only present if the skb contains more than just the
+ * IEEE 802.11 header.
+ */
+ unsigned int l2pad = (skb->len > header_length) ?
+ L2PAD_SIZE(header_length) : 0;

if (!l2pad)
return;

- memmove(skb->data + header_length, skb->data + header_length + l2pad,
- skb->len - header_length - l2pad);
-
- skb_trim(skb, skb->len - l2pad);
+ memmove(skb->data + l2pad, skb->data, header_length);
+ skb_pull(skb, l2pad);
}

static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
--
1.7.2.3


2010-12-17 16:33:53

by Walter Goldens

[permalink] [raw]
Subject: Re: [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use


> > > Odd I have been testing this while stresstesting
> the card,
> > > and either
> > > unplugging, rmmod or ifdown, and I couldn't
> > > reproduce any crashes. Has the stacktrace changed
> after
> > > these patches?
> >
> > I can confirm when the rt2800usb is loaded and an
> rt3070 chip is connected to
> > a network, running 'rmmod rt2800usb rt2x00lib
> rt2x00usb rt2800lib' causes
> > immediate system hang (and hard-reset).
>
> FWIW, I did not test this case.? I only tested
> hot-unplug of the
> USB device.? However, I think usually when the network
> interface
> is up the module use count should be incremented so that
> you
> cannot unload the module.
>


Hi, Johannes

I can rmmod the zd1211rw for example, even the interface is up and connected to a network, whereas the rt2800usb forces the system to freeze. Why the difference?

Walter




2010-12-13 11:40:09

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 03/17] rt2x00: Add RF chip definition

From: RA-Jay Hung <[email protected]>

Add RF chip definition

Signed-off-by: RA-Jay Hung <[email protected]>
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2800.h | 10 ++++++++--
1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 03f9fa1..9ea0961 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -46,8 +46,11 @@
* RF2020 2.4G B/G
* RF3021 2.4G 1T2R
* RF3022 2.4G 2T2R
- * RF3052 2.4G 2T2R
- * RF3320 2.4G 1T1R
+ * RF3052 2.4G/5G 2T2R
+ * RF2853 2.4G/5G 3T3R
+ * RF3320 2.4G 1T1R(RT3350/RT3370/RT3390)
+ * RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
+ * RF3853 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
*/
#define RF2820 0x0001
#define RF2850 0x0002
@@ -58,7 +61,10 @@
#define RF3021 0x0007
#define RF3022 0x0008
#define RF3052 0x0009
+#define RF2853 0x000a
#define RF3320 0x000b
+#define RF3322 0x000c
+#define RF3853 0x000d

/*
* Chipset revisions.
--
1.7.2.3


2010-12-13 11:40:26

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 10/17] rt2x00: Protect queue control with mutex

Add wrapper functions in rt2x00queue.c to
start & stop queues. This control must be protected
using a mutex.

Queues can also be paused which will halt the flow
of packets between the driver and mac80211. This doesn't
require a mutex protection.

Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00.h | 52 ++++++++
drivers/net/wireless/rt2x00/rt2x00config.c | 4 +-
drivers/net/wireless/rt2x00/rt2x00debug.c | 5 +-
drivers/net/wireless/rt2x00/rt2x00dev.c | 22 +---
drivers/net/wireless/rt2x00/rt2x00lib.h | 9 --
drivers/net/wireless/rt2x00/rt2x00mac.c | 8 +-
drivers/net/wireless/rt2x00/rt2x00queue.c | 130 ++++++++++++++++++--
drivers/net/wireless/rt2x00/rt2x00queue.h | 23 ++++
drivers/net/wireless/rt2x00/rt2x00usb.c | 190 ++++++++++++++--------------
9 files changed, 302 insertions(+), 141 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 617d68f..511ca91 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -1072,6 +1072,58 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
enum queue_index index);

+/**
+ * rt2x00queue_pause_queue - Pause a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will pause the data queue locally, preventing
+ * new frames to be added to the queue (while the hardware is
+ * still allowed to run).
+ */
+void rt2x00queue_pause_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_unpause_queue - unpause a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will unpause the data queue locally, allowing
+ * new frames to be added to the queue again.
+ */
+void rt2x00queue_unpause_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_start_queue - Start a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will start handling all pending frames in the queue.
+ */
+void rt2x00queue_start_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_stop_queue - Halt a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will stop all pending frames in the queue.
+ */
+void rt2x00queue_stop_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_start_queues - Start all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * This function will loop through all available queues to start them
+ */
+void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00queue_stop_queues - Halt all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * This function will loop through all available queues to stop
+ * any pending frames.
+ */
+void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev);
+
/*
* Debugfs handlers.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index d2f1f0a..70ca937 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -146,7 +146,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* else the changes will be ignored by the device.
*/
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx);
+ rt2x00queue_stop_queue(rt2x00dev->rx);

/*
* Write new antenna setup to device and reset the link tuner.
@@ -160,7 +160,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
memcpy(active, &config, sizeof(config));

if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2x00dev->ops->lib->start_queue(rt2x00dev->rx);
+ rt2x00queue_start_queue(rt2x00dev->rx);
}

void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 64dfb1f..c92db32 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -339,12 +339,13 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file,
return -ENOMEM;

temp = data +
- sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdma done\tdone\n");
+ sprintf(data, "qid\tflags\t\tcount\tlimit\tlength\tindex\tdma done\tdone\n");

queue_for_each(intf->rt2x00dev, queue) {
spin_lock_irqsave(&queue->index_lock, irqflags);

- temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid,
+ temp += sprintf(temp, "%d\t0x%.8x\t%d\t%d\t%d\t%d\t%d\t\t%d\n",
+ queue->qid, (unsigned int)queue->flags,
queue->count, queue->limit, queue->length,
queue->index[Q_INDEX],
queue->index[Q_INDEX_DMA_DONE],
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 8d864b6..fbc98dd 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -66,9 +66,9 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags);

/*
- * Enable RX.
+ * Enable queues.
*/
- rt2x00dev->ops->lib->start_queue(rt2x00dev->rx);
+ rt2x00queue_start_queues(rt2x00dev);
rt2x00link_start_tuner(rt2x00dev);

/*
@@ -76,11 +76,6 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
*/
rt2x00link_start_watchdog(rt2x00dev);

- /*
- * Start the TX queues.
- */
- ieee80211_wake_queues(rt2x00dev->hw);
-
return 0;
}

@@ -90,21 +85,15 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
return;

/*
- * Stop the TX queues in mac80211.
- */
- ieee80211_stop_queues(rt2x00dev->hw);
- rt2x00queue_stop_queues(rt2x00dev);
-
- /*
* Stop watchdog monitoring.
*/
rt2x00link_stop_watchdog(rt2x00dev);

/*
- * Disable RX.
+ * Stop all queues
*/
rt2x00link_stop_tuner(rt2x00dev);
- rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx);
+ rt2x00queue_stop_queues(rt2x00dev);

/*
* Disable radio.
@@ -249,7 +238,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
unsigned int header_length, i;
u8 rate_idx, rate_flags, retry_rates;
u8 skbdesc_flags = skbdesc->flags;
@@ -400,7 +388,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* is reenabled when the txdone handler has finished.
*/
if (!rt2x00queue_threshold(entry->queue))
- ieee80211_wake_queue(rt2x00dev->hw, qid);
+ rt2x00queue_unpause_queue(entry->queue);
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);

diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 2cf68f8..a105c50 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -178,15 +178,6 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);

/**
- * rt2x00queue_stop_queues - Halt all data queues
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- *
- * This function will loop through all available queues to stop
- * any pending outgoing frames.
- */
-void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev);
-
-/**
* rt2x00queue_init_queues - Initialize all data queues
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 6713f1a..c4abb20 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -104,7 +104,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
enum data_queue_qid qid = skb_get_queue_mapping(skb);
- struct data_queue *queue;
+ struct data_queue *queue = NULL;

/*
* Mac80211 might be calling this function while we are trying
@@ -153,7 +153,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
goto exit_fail;

if (rt2x00queue_threshold(queue))
- ieee80211_stop_queue(rt2x00dev->hw, qid);
+ rt2x00queue_pause_queue(queue);

return NETDEV_TX_OK;

@@ -352,7 +352,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
* if for any reason the link tuner must be reset, this will be
* handled by rt2x00lib_config().
*/
- rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx);
+ rt2x00queue_stop_queue(rt2x00dev->rx);

/*
* When we've just turned on the radio, we want to reprogram
@@ -370,7 +370,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);

/* Turn RX back on */
- rt2x00dev->ops->lib->start_queue(rt2x00dev->rx);
+ rt2x00queue_start_queue(rt2x00dev->rx);

return 0;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 2af6cea..558965f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -585,7 +585,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
rt2x00queue_free_skb(intf->beacon);

if (!enable_beacon) {
- rt2x00dev->ops->lib->stop_queue(intf->beacon->queue);
+ rt2x00queue_stop_queue(intf->beacon->queue);
mutex_unlock(&intf->beacon_skb_mutex);
return 0;
}
@@ -738,6 +738,125 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
spin_unlock_irqrestore(&queue->index_lock, irqflags);
}

+void rt2x00queue_pause_queue(struct data_queue *queue)
+{
+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+ !test_bit(QUEUE_STARTED, &queue->flags) ||
+ test_and_set_bit(QUEUE_PAUSED, &queue->flags))
+ return;
+
+ switch (queue->qid) {
+ case QID_AC_BE:
+ case QID_AC_BK:
+ case QID_AC_VI:
+ case QID_AC_VO:
+ /*
+ * For TX queues, we have to disable the queue
+ * inside mac80211.
+ */
+ ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid);
+ break;
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue);
+
+void rt2x00queue_unpause_queue(struct data_queue *queue)
+{
+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+ !test_bit(QUEUE_STARTED, &queue->flags) ||
+ !test_and_clear_bit(QUEUE_PAUSED, &queue->flags))
+ return;
+
+ switch (queue->qid) {
+ case QID_AC_BE:
+ case QID_AC_BK:
+ case QID_AC_VI:
+ case QID_AC_VO:
+ /*
+ * For TX queues, we have to enable the queue
+ * inside mac80211.
+ */
+ ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
+ break;
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_unpause_queue);
+
+void rt2x00queue_start_queue(struct data_queue *queue)
+{
+ mutex_lock(&queue->status_lock);
+
+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+ test_and_set_bit(QUEUE_STARTED, &queue->flags)) {
+ mutex_unlock(&queue->status_lock);
+ return;
+ }
+
+ set_bit(QUEUE_PAUSED, &queue->flags);
+
+ queue->rt2x00dev->ops->lib->start_queue(queue);
+
+ rt2x00queue_unpause_queue(queue);
+
+ mutex_unlock(&queue->status_lock);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_start_queue);
+
+void rt2x00queue_stop_queue(struct data_queue *queue)
+{
+ mutex_lock(&queue->status_lock);
+
+ if (!test_and_clear_bit(QUEUE_STARTED, &queue->flags)) {
+ mutex_unlock(&queue->status_lock);
+ return;
+ }
+
+ rt2x00queue_pause_queue(queue);
+
+ queue->rt2x00dev->ops->lib->stop_queue(queue);
+
+ mutex_unlock(&queue->status_lock);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_stop_queue);
+
+void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ /*
+ * rt2x00queue_start_queue will call ieee80211_wake_queue
+ * for each queue after is has been properly initialized.
+ */
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_start_queue(queue);
+
+ rt2x00queue_start_queue(rt2x00dev->rx);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_start_queues);
+
+void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ /*
+ * rt2x00queue_stop_queue will call ieee80211_stop_queue
+ * as well, but we are completely shutting doing everything
+ * now, so it is much safer to stop all TX queues at once,
+ * and use rt2x00queue_stop_queue for cleaning up.
+ */
+ ieee80211_stop_queues(rt2x00dev->hw);
+
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_stop_queue(queue);
+
+ rt2x00queue_stop_queue(rt2x00dev->rx);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_stop_queues);
+
static void rt2x00queue_reset(struct data_queue *queue)
{
unsigned long irqflags;
@@ -756,14 +875,6 @@ static void rt2x00queue_reset(struct data_queue *queue)
spin_unlock_irqrestore(&queue->index_lock, irqflags);
}

-void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
-
- txall_queue_for_each(rt2x00dev, queue)
- rt2x00dev->ops->lib->stop_queue(queue);
-}
-
void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
@@ -905,6 +1016,7 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue, enum data_queue_qid qid)
{
+ mutex_init(&queue->status_lock);
spin_lock_init(&queue->index_lock);

queue->rt2x00dev = rt2x00dev;
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 29b051a..baa39b7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -392,12 +392,32 @@ enum queue_index {
};

/**
+ * enum data_queue_flags: Status flags for data queues
+ *
+ * @QUEUE_STARTED: The queue has been started. Fox RX queues this means the
+ * device might be DMA'ing skbuffers. TX queues will accept skbuffers to
+ * be transmitted and beacon queues will start beaconing the configured
+ * beacons.
+ * @QUEUE_PAUSED: The queue has been started but is currently paused.
+ * When this bit is set, the queue has been stopped in mac80211,
+ * preventing new frames to be enqueued. However, a few frames
+ * might still appear shortly after the pausing...
+ */
+enum data_queue_flags {
+ QUEUE_STARTED,
+ QUEUE_PAUSED,
+};
+
+/**
* struct data_queue: Data queue
*
* @rt2x00dev: Pointer to main &struct rt2x00dev where this queue belongs to.
* @entries: Base address of the &struct queue_entry which are
* part of this queue.
* @qid: The queue identification, see &enum data_queue_qid.
+ * @flags: Entry flags, see &enum queue_entry_flags.
+ * @status_lock: The mutex for protecting the start/stop/flush
+ * handling on this queue.
* @index_lock: Spinlock to protect index handling. Whenever @index, @index_done or
* @index_crypt needs to be changed this lock should be grabbed to prevent
* index corruption due to concurrency.
@@ -421,8 +441,11 @@ struct data_queue {
struct queue_entry *entries;

enum data_queue_qid qid;
+ unsigned long flags;

+ struct mutex status_lock;
spinlock_t index_lock;
+
unsigned int count;
unsigned short limit;
unsigned short threshold;
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index d4361dc..fca29ae 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -261,6 +261,89 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
}
}

+/*
+ * RX data handlers.
+ */
+static void rt2x00usb_work_rxdone(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, rxdone_work);
+ struct queue_entry *entry;
+ struct skb_frame_desc *skbdesc;
+ u8 rxd[32];
+
+ while (!rt2x00queue_empty(rt2x00dev->rx)) {
+ entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE);
+
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ break;
+
+ /*
+ * Fill in desc fields of the skb descriptor
+ */
+ skbdesc = get_skb_frame_desc(entry->skb);
+ skbdesc->desc = rxd;
+ skbdesc->desc_len = entry->queue->desc_size;
+
+ /*
+ * Send the frame to rt2x00lib for further processing.
+ */
+ rt2x00lib_rxdone(entry);
+ }
+}
+
+static void rt2x00usb_interrupt_rxdone(struct urb *urb)
+{
+ struct queue_entry *entry = (struct queue_entry *)urb->context;
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+
+ if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ return;
+
+ /*
+ * Report the frame as DMA done
+ */
+ rt2x00lib_dmadone(entry);
+
+ /*
+ * Check if the received data is simply too small
+ * to be actually valid, or if the urb is signaling
+ * a problem.
+ */
+ if (urb->actual_length < entry->queue->desc_size || urb->status)
+ set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
+
+ /*
+ * Schedule the delayed work for reading the RX status
+ * from the device.
+ */
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
+}
+
+static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+ struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+ int status;
+
+ if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ return;
+
+ usb_fill_bulk_urb(entry_priv->urb, usb_dev,
+ usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint),
+ entry->skb->data, entry->skb->len,
+ rt2x00usb_interrupt_rxdone, entry);
+
+ status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+ if (status) {
+ if (status == -ENODEV)
+ clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
+ set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
+ rt2x00lib_dmadone(entry);
+ }
+}
+
void rt2x00usb_kick_queue(struct data_queue *queue)
{
switch (queue->qid) {
@@ -272,6 +355,11 @@ void rt2x00usb_kick_queue(struct data_queue *queue)
rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
rt2x00usb_kick_tx_entry);
break;
+ case QID_RX:
+ if (!rt2x00queue_full(queue))
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00usb_kick_rx_entry);
+ break;
default:
break;
}
@@ -307,7 +395,6 @@ EXPORT_SYMBOL_GPL(rt2x00usb_stop_queue);
static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- unsigned short threshold = queue->threshold;

WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
" invoke forced forced reset\n", queue->qid);
@@ -315,18 +402,8 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
/*
* Temporarily disable the TX queue, this will force mac80211
* to use the other queues until this queue has been restored.
- *
- * Set the queue threshold to the queue limit. This prevents the
- * queue from being enabled during the txdone handler.
*/
- queue->threshold = queue->limit;
- ieee80211_stop_queue(rt2x00dev->hw, queue->qid);
-
- /*
- * Kill all entries in the queue, afterwards we need to
- * wait a bit for all URBs to be cancelled.
- */
- rt2x00usb_stop_queue(queue);
+ rt2x00queue_stop_queue(queue);

/*
* In case that a driver has overriden the txdone_work
@@ -338,8 +415,7 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
* The queue has been reset, and mac80211 is allowed to use the
* queue again.
*/
- queue->threshold = threshold;
- ieee80211_wake_queue(rt2x00dev->hw, queue->qid);
+ rt2x00queue_start_queue(queue);
}

static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
@@ -366,73 +442,12 @@ void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);

/*
- * RX data handlers.
- */
-static void rt2x00usb_work_rxdone(struct work_struct *work)
-{
- struct rt2x00_dev *rt2x00dev =
- container_of(work, struct rt2x00_dev, rxdone_work);
- struct queue_entry *entry;
- struct skb_frame_desc *skbdesc;
- u8 rxd[32];
-
- while (!rt2x00queue_empty(rt2x00dev->rx)) {
- entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE);
-
- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
- break;
-
- /*
- * Fill in desc fields of the skb descriptor
- */
- skbdesc = get_skb_frame_desc(entry->skb);
- skbdesc->desc = rxd;
- skbdesc->desc_len = entry->queue->desc_size;
-
- /*
- * Send the frame to rt2x00lib for further processing.
- */
- rt2x00lib_rxdone(entry);
- }
-}
-
-static void rt2x00usb_interrupt_rxdone(struct urb *urb)
-{
- struct queue_entry *entry = (struct queue_entry *)urb->context;
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-
- if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
- return;
-
- /*
- * Report the frame as DMA done
- */
- rt2x00lib_dmadone(entry);
-
- /*
- * Check if the received data is simply too small
- * to be actually valid, or if the urb is signaling
- * a problem.
- */
- if (urb->actual_length < entry->queue->desc_size || urb->status)
- set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
-
- /*
- * Schedule the delayed work for reading the RX status
- * from the device.
- */
- ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
-}
-
-/*
* Radio handlers
*/
void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
REGISTER_TIMEOUT);
-
- rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx);
}
EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);

@@ -441,31 +456,10 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
*/
void rt2x00usb_clear_entry(struct queue_entry *entry)
{
- struct usb_device *usb_dev =
- to_usb_device_intf(entry->queue->rt2x00dev->dev);
- struct queue_entry_priv_usb *entry_priv = entry->priv_data;
- int pipe;
- int status;
-
entry->flags = 0;

- if (entry->queue->qid == QID_RX) {
- pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
- usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
- entry->skb->data, entry->skb->len,
- rt2x00usb_interrupt_rxdone, entry);
-
- set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-
- status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
- if (status) {
- if (status == -ENODEV)
- clear_bit(DEVICE_STATE_PRESENT,
- &entry->queue->rt2x00dev->flags);
- set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
- rt2x00lib_dmadone(entry);
- }
- }
+ if (entry->queue->qid == QID_RX)
+ rt2x00usb_kick_rx_entry(entry);
}
EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);

--
1.7.2.3


2010-12-14 19:24:29

by Johannes Stezenbach

[permalink] [raw]
Subject: Re: [PATCH 14/17] rt2x00: Fix WMM Queue naming

Hi,

On Tue, Dec 14, 2010 at 07:44:35PM +0100, Ivo Van Doorn wrote:
> >> The Queue names were incorrectly copied from the legacy drivers,
> >> as a result the queue names were inversed to what was expected.
> >>
> >> This renames the queues using this mapping:
> >> ? ? ? QID_AC_BK -> QID_AC_VO (priority 0)
> >> ? ? ? QID_AC_BE -> QID_AC_VI (priority 1)
> >> ? ? ? QID_AC_VI -> QID_AC_BE (priority 2)
> >> ? ? ? QID_AC_VO -> QID_AC_BK (priority 3)
> >>
> >> Note that this was a naming problem only, which didn't affect
> >> the assignment of frames to their respective queues.
> >>
> >> Signed-off-by: Ivo van Doorn <[email protected]>
> >
> > Ivo, due to the latest info from Ralink I'd say we should drop this patch
> > and instead introduce a mac80211_to_rt2x00_qid mapper that maps from
> > ieee80211_ac_numbers to data_queue_qid.
> >
> > This patch doesn't cause any harm, but we would have to revert it partly
> > if we introduce the queue mapping as needed by the rt2x00 devices.
>
> I don't agree, this patch can safely be applied, since the mapping
> is in the endpoint assignment, rather the register value usage,
> I think the more optimal solution is fixing rt2x00usb_assign_endpoints.
> In there it currently assigns endpoints assuming the first endpoint
> is the highest priority, while we should be able to simply swap that
> to invert the logic.

Inverting is not enough since the first OUT EP (EP1) is AC_BE,
while AC_BK (lowest priority) is EP2. This corresponds to the
to the AC -> ACI mapping from 802.11 Table 7-36 in section
"7.3.2.29 EDCA Parameter Set element". Probably the rationale
is that ACI value 0 should be the "default" AC.

Johannes

2010-12-13 11:40:33

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 14/17] rt2x00: Fix WMM Queue naming

The Queue names were incorrectly copied from the legacy drivers,
as a result the queue names were inversed to what was expected.

This renames the queues using this mapping:
QID_AC_BK -> QID_AC_VO (priority 0)
QID_AC_BE -> QID_AC_VI (priority 1)
QID_AC_VI -> QID_AC_BE (priority 2)
QID_AC_VO -> QID_AC_BK (priority 3)

Note that this was a naming problem only, which didn't affect
the assignment of frames to their respective queues.

Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2400pci.c | 12 +++---
drivers/net/wireless/rt2x00/rt2500pci.c | 12 +++---
drivers/net/wireless/rt2x00/rt2800.h | 44 ++++++++++----------
drivers/net/wireless/rt2x00/rt2800pci.c | 4 +-
drivers/net/wireless/rt2x00/rt2x00queue.c | 18 ++++----
drivers/net/wireless/rt2x00/rt2x00queue.h | 12 +++---
drivers/net/wireless/rt2x00/rt2x00usb.c | 8 ++--
drivers/net/wireless/rt2x00/rt61pci.c | 16 ++++----
drivers/net/wireless/rt2x00/rt61pci.h | 62 ++++++++++++++--------------
drivers/net/wireless/rt2x00/rt73usb.h | 36 ++++++++--------
10 files changed, 112 insertions(+), 112 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 2fc6ca5..54ca49a 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -664,12 +664,12 @@ static void rt2400pci_kick_queue(struct data_queue *queue)
u32 reg;

switch (queue->qid) {
- case QID_AC_BE:
+ case QID_AC_VO:
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
break;
- case QID_AC_BK:
+ case QID_AC_VI:
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
@@ -690,8 +690,8 @@ static void rt2400pci_stop_queue(struct data_queue *queue)
u32 reg;

switch (queue->qid) {
- case QID_AC_BE:
- case QID_AC_BK:
+ case QID_AC_VO:
+ case QID_AC_VI:
case QID_ATIM:
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
@@ -1322,13 +1322,13 @@ static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance)
* 4 - Priority ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
- rt2400pci_txdone(rt2x00dev, QID_AC_BE);
+ rt2400pci_txdone(rt2x00dev, QID_AC_VO);

/*
* 5 - Tx ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
- rt2400pci_txdone(rt2x00dev, QID_AC_BK);
+ rt2400pci_txdone(rt2x00dev, QID_AC_VI);

/* Enable interrupts again. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index d67f911..a9ff26a 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -754,12 +754,12 @@ static void rt2500pci_kick_queue(struct data_queue *queue)
u32 reg;

switch (queue->qid) {
- case QID_AC_BE:
+ case QID_AC_VO:
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
break;
- case QID_AC_BK:
+ case QID_AC_VI:
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
@@ -780,8 +780,8 @@ static void rt2500pci_stop_queue(struct data_queue *queue)
u32 reg;

switch (queue->qid) {
- case QID_AC_BE:
- case QID_AC_BK:
+ case QID_AC_VO:
+ case QID_AC_VI:
case QID_ATIM:
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
@@ -1455,13 +1455,13 @@ static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance)
* 4 - Priority ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
- rt2500pci_txdone(rt2x00dev, QID_AC_BE);
+ rt2500pci_txdone(rt2x00dev, QID_AC_VO);

/*
* 5 - Tx ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
- rt2500pci_txdone(rt2x00dev, QID_AC_BK);
+ rt2500pci_txdone(rt2x00dev, QID_AC_VI);

/* Enable interrupts again. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 9ea0961..4c55e85 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -213,10 +213,10 @@

/*
* WMM_AIFSN_CFG: Aifsn for each EDCA AC
- * AIFSN0: AC_BE
- * AIFSN1: AC_BK
- * AIFSN2: AC_VI
- * AIFSN3: AC_VO
+ * AIFSN0: AC_VO
+ * AIFSN1: AC_VI
+ * AIFSN2: AC_BE
+ * AIFSN3: AC_BK
*/
#define WMM_AIFSN_CFG 0x0214
#define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f)
@@ -226,10 +226,10 @@

/*
* WMM_CWMIN_CSR: CWmin for each EDCA AC
- * CWMIN0: AC_BE
- * CWMIN1: AC_BK
- * CWMIN2: AC_VI
- * CWMIN3: AC_VO
+ * CWMIN0: AC_VO
+ * CWMIN1: AC_VI
+ * CWMIN2: AC_BE
+ * CWMIN3: AC_BK
*/
#define WMM_CWMIN_CFG 0x0218
#define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f)
@@ -239,10 +239,10 @@

/*
* WMM_CWMAX_CSR: CWmax for each EDCA AC
- * CWMAX0: AC_BE
- * CWMAX1: AC_BK
- * CWMAX2: AC_VI
- * CWMAX3: AC_VO
+ * CWMAX0: AC_VO
+ * CWMAX1: AC_VI
+ * CWMAX2: AC_BE
+ * CWMAX3: AC_BK
*/
#define WMM_CWMAX_CFG 0x021c
#define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f)
@@ -251,18 +251,18 @@
#define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000)

/*
- * AC_TXOP0: AC_BK/AC_BE TXOP register
- * AC0TXOP: AC_BK in unit of 32us
- * AC1TXOP: AC_BE in unit of 32us
+ * AC_TXOP0: AC_VO/AC_VI TXOP register
+ * AC0TXOP: AC_VO in unit of 32us
+ * AC1TXOP: AC_VI in unit of 32us
*/
#define WMM_TXOP0_CFG 0x0220
#define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff)
#define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000)

/*
- * AC_TXOP1: AC_VO/AC_VI TXOP register
- * AC2TXOP: AC_VI in unit of 32us
- * AC3TXOP: AC_VO in unit of 32us
+ * AC_TXOP1: AC_BE/AC_BK TXOP register
+ * AC2TXOP: AC_BE in unit of 32us
+ * AC3TXOP: AC_BK in unit of 32us
*/
#define WMM_TXOP1_CFG 0x0224
#define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff)
@@ -288,7 +288,7 @@
#define MCU_CMD_CFG 0x022c

/*
- * AC_BK register offsets
+ * AC_VO register offsets
*/
#define TX_BASE_PTR0 0x0230
#define TX_MAX_CNT0 0x0234
@@ -296,7 +296,7 @@
#define TX_DTX_IDX0 0x023c

/*
- * AC_BE register offsets
+ * AC_VI register offsets
*/
#define TX_BASE_PTR1 0x0240
#define TX_MAX_CNT1 0x0244
@@ -304,7 +304,7 @@
#define TX_DTX_IDX1 0x024c

/*
- * AC_VI register offsets
+ * AC_BE register offsets
*/
#define TX_BASE_PTR2 0x0250
#define TX_MAX_CNT2 0x0254
@@ -312,7 +312,7 @@
#define TX_DTX_IDX2 0x025c

/*
- * AC_VO register offsets
+ * AC_BK register offsets
*/
#define TX_BASE_PTR3 0x0260
#define TX_MAX_CNT3 0x0264
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 195f0be3..403013f 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -217,10 +217,10 @@ static void rt2800pci_kick_queue(struct data_queue *queue)
struct queue_entry *entry;

switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
case QID_AC_BE:
case QID_AC_BK:
- case QID_AC_VI:
- case QID_AC_VO:
entry = rt2x00queue_get_entry(queue, Q_INDEX);
rt2800_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), entry->entry_idx);
break;
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 52cc92d..ca82b3a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -746,10 +746,10 @@ void rt2x00queue_pause_queue(struct data_queue *queue)
return;

switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
case QID_AC_BE:
case QID_AC_BK:
- case QID_AC_VI:
- case QID_AC_VO:
/*
* For TX queues, we have to disable the queue
* inside mac80211.
@@ -770,10 +770,10 @@ void rt2x00queue_unpause_queue(struct data_queue *queue)
return;

switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
case QID_AC_BE:
case QID_AC_BK:
- case QID_AC_VI:
- case QID_AC_VO:
/*
* For TX queues, we have to enable the queue
* inside mac80211.
@@ -834,10 +834,10 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
unsigned int i;
bool started;
bool tx_queue =
- (queue->qid == QID_AC_BE) ||
- (queue->qid == QID_AC_BK) ||
+ (queue->qid == QID_AC_VO) ||
(queue->qid == QID_AC_VI) ||
- (queue->qid == QID_AC_VO);
+ (queue->qid == QID_AC_BE) ||
+ (queue->qid == QID_AC_BK);

mutex_lock(&queue->status_lock);

@@ -1141,7 +1141,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
/*
* Initialize queue parameters.
* RX: qid = QID_RX
- * TX: qid = QID_AC_BE + index
+ * TX: qid = QID_AC_VO + index
* TX: cw_min: 2^5 = 32.
* TX: cw_max: 2^10 = 1024.
* BCN: qid = QID_BEACON
@@ -1149,7 +1149,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
*/
rt2x00queue_init(rt2x00dev, rt2x00dev->rx, QID_RX);

- qid = QID_AC_BE;
+ qid = QID_AC_VO;
tx_queue_for_each(rt2x00dev, queue)
rt2x00queue_init(rt2x00dev, queue, qid++);

diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 4765934..fab8e26 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -45,10 +45,10 @@
/**
* enum data_queue_qid: Queue identification
*
+ * @QID_AC_VO: AC VO queue
+ * @QID_AC_VI: AC VI queue
* @QID_AC_BE: AC BE queue
* @QID_AC_BK: AC BK queue
- * @QID_AC_VI: AC VI queue
- * @QID_AC_VO: AC VO queue
* @QID_HCCA: HCCA queue
* @QID_MGMT: MGMT queue (prio queue)
* @QID_RX: RX queue
@@ -57,10 +57,10 @@
* @QID_ATIM: Atim queue (value unspeficied, don't send it to device)
*/
enum data_queue_qid {
- QID_AC_BE = 0,
- QID_AC_BK = 1,
- QID_AC_VI = 2,
- QID_AC_VO = 3,
+ QID_AC_VO = 0,
+ QID_AC_VI = 1,
+ QID_AC_BE = 2,
+ QID_AC_BK = 3,
QID_HCCA = 4,
QID_MGMT = 13,
QID_RX = 14,
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 8a16b51..1a9937d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -353,10 +353,10 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
void rt2x00usb_kick_queue(struct data_queue *queue)
{
switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
case QID_AC_BE:
case QID_AC_BK:
- case QID_AC_VI:
- case QID_AC_VO:
if (!rt2x00queue_empty(queue))
rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
rt2x00usb_kick_tx_entry);
@@ -403,10 +403,10 @@ void rt2x00usb_flush_queue(struct data_queue *queue)
* Obtain the queue completion handler
*/
switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
case QID_AC_BE:
case QID_AC_BK:
- case QID_AC_VI:
- case QID_AC_VO:
completion = &queue->rt2x00dev->txdone_work;
break;
case QID_RX:
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 7156b78..9405b10 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1171,22 +1171,22 @@ static void rt61pci_kick_queue(struct data_queue *queue)
u32 reg;

switch (queue->qid) {
- case QID_AC_BE:
+ case QID_AC_VO:
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
- case QID_AC_BK:
+ case QID_AC_VI:
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, 1);
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
- case QID_AC_VI:
+ case QID_AC_BE:
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, 1);
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
- case QID_AC_VO:
+ case QID_AC_BK:
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, 1);
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
@@ -1202,22 +1202,22 @@ static void rt61pci_stop_queue(struct data_queue *queue)
u32 reg;

switch (queue->qid) {
- case QID_AC_BE:
+ case QID_AC_VO:
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, 1);
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
- case QID_AC_BK:
+ case QID_AC_VI:
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, 1);
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
- case QID_AC_VI:
+ case QID_AC_BE:
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, 1);
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
- case QID_AC_VO:
+ case QID_AC_BK:
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, 1);
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index afc803b..e3cd6db 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -784,25 +784,25 @@ struct hw_pairwise_ta_entry {
*/

/*
- * AC0_BASE_CSR: AC_BK base address.
+ * AC0_BASE_CSR: AC_VO base address.
*/
#define AC0_BASE_CSR 0x3400
#define AC0_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)

/*
- * AC1_BASE_CSR: AC_BE base address.
+ * AC1_BASE_CSR: AC_VI base address.
*/
#define AC1_BASE_CSR 0x3404
#define AC1_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)

/*
- * AC2_BASE_CSR: AC_VI base address.
+ * AC2_BASE_CSR: AC_BE base address.
*/
#define AC2_BASE_CSR 0x3408
#define AC2_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)

/*
- * AC3_BASE_CSR: AC_VO base address.
+ * AC3_BASE_CSR: AC_BK base address.
*/
#define AC3_BASE_CSR 0x340c
#define AC3_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
@@ -814,7 +814,7 @@ struct hw_pairwise_ta_entry {
#define MGMT_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)

/*
- * TX_RING_CSR0: TX Ring size for AC_BK, AC_BE, AC_VI, AC_VO.
+ * TX_RING_CSR0: TX Ring size for AC_VO, AC_VI, AC_BE, AC_BK.
*/
#define TX_RING_CSR0 0x3418
#define TX_RING_CSR0_AC0_RING_SIZE FIELD32(0x000000ff)
@@ -833,10 +833,10 @@ struct hw_pairwise_ta_entry {

/*
* AIFSN_CSR: AIFSN for each EDCA AC.
- * AIFSN0: For AC_BK.
- * AIFSN1: For AC_BE.
- * AIFSN2: For AC_VI.
- * AIFSN3: For AC_VO.
+ * AIFSN0: For AC_VO.
+ * AIFSN1: For AC_VI.
+ * AIFSN2: For AC_BE.
+ * AIFSN3: For AC_BK.
*/
#define AIFSN_CSR 0x3420
#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
@@ -846,10 +846,10 @@ struct hw_pairwise_ta_entry {

/*
* CWMIN_CSR: CWmin for each EDCA AC.
- * CWMIN0: For AC_BK.
- * CWMIN1: For AC_BE.
- * CWMIN2: For AC_VI.
- * CWMIN3: For AC_VO.
+ * CWMIN0: For AC_VO.
+ * CWMIN1: For AC_VI.
+ * CWMIN2: For AC_BE.
+ * CWMIN3: For AC_BK.
*/
#define CWMIN_CSR 0x3424
#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
@@ -859,10 +859,10 @@ struct hw_pairwise_ta_entry {

/*
* CWMAX_CSR: CWmax for each EDCA AC.
- * CWMAX0: For AC_BK.
- * CWMAX1: For AC_BE.
- * CWMAX2: For AC_VI.
- * CWMAX3: For AC_VO.
+ * CWMAX0: For AC_VO.
+ * CWMAX1: For AC_VI.
+ * CWMAX2: For AC_BE.
+ * CWMAX3: For AC_BK.
*/
#define CWMAX_CSR 0x3428
#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
@@ -883,14 +883,14 @@ struct hw_pairwise_ta_entry {

/*
* TX_CNTL_CSR: KICK/Abort TX.
- * KICK_TX_AC0: For AC_BK.
- * KICK_TX_AC1: For AC_BE.
- * KICK_TX_AC2: For AC_VI.
- * KICK_TX_AC3: For AC_VO.
- * ABORT_TX_AC0: For AC_BK.
- * ABORT_TX_AC1: For AC_BE.
- * ABORT_TX_AC2: For AC_VI.
- * ABORT_TX_AC3: For AC_VO.
+ * KICK_TX_AC0: For AC_VO.
+ * KICK_TX_AC1: For AC_VI.
+ * KICK_TX_AC2: For AC_BE.
+ * KICK_TX_AC3: For AC_BK.
+ * ABORT_TX_AC0: For AC_VO.
+ * ABORT_TX_AC1: For AC_VI.
+ * ABORT_TX_AC2: For AC_BE.
+ * ABORT_TX_AC3: For AC_BK.
*/
#define TX_CNTL_CSR 0x3430
#define TX_CNTL_CSR_KICK_TX_AC0 FIELD32(0x00000001)
@@ -1010,18 +1010,18 @@ struct hw_pairwise_ta_entry {
#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040)

/*
- * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
- * AC0_TX_OP: For AC_BK, in unit of 32us.
- * AC1_TX_OP: For AC_BE, in unit of 32us.
+ * AC_TXOP_CSR0: AC_VO/AC_VI TXOP register.
+ * AC0_TX_OP: For AC_VO, in unit of 32us.
+ * AC1_TX_OP: For AC_VI, in unit of 32us.
*/
#define AC_TXOP_CSR0 0x3474
#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff)
#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000)

/*
- * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
- * AC2_TX_OP: For AC_VI, in unit of 32us.
- * AC3_TX_OP: For AC_VO, in unit of 32us.
+ * AC_TXOP_CSR1: AC_BE/AC_BK TXOP register.
+ * AC2_TX_OP: For AC_BE, in unit of 32us.
+ * AC3_TX_OP: For AC_BK, in unit of 32us.
*/
#define AC_TXOP_CSR1 0x3478
#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 1315ce5..9f6b470 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -689,10 +689,10 @@ struct hw_pairwise_ta_entry {

/*
* AIFSN_CSR: AIFSN for each EDCA AC.
- * AIFSN0: For AC_BK.
- * AIFSN1: For AC_BE.
- * AIFSN2: For AC_VI.
- * AIFSN3: For AC_VO.
+ * AIFSN0: For AC_VO.
+ * AIFSN1: For AC_VI.
+ * AIFSN2: For AC_BE.
+ * AIFSN3: For AC_BK.
*/
#define AIFSN_CSR 0x0400
#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
@@ -702,10 +702,10 @@ struct hw_pairwise_ta_entry {

/*
* CWMIN_CSR: CWmin for each EDCA AC.
- * CWMIN0: For AC_BK.
- * CWMIN1: For AC_BE.
- * CWMIN2: For AC_VI.
- * CWMIN3: For AC_VO.
+ * CWMIN0: For AC_VO.
+ * CWMIN1: For AC_VI.
+ * CWMIN2: For AC_BE.
+ * CWMIN3: For AC_BK.
*/
#define CWMIN_CSR 0x0404
#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
@@ -715,10 +715,10 @@ struct hw_pairwise_ta_entry {

/*
* CWMAX_CSR: CWmax for each EDCA AC.
- * CWMAX0: For AC_BK.
- * CWMAX1: For AC_BE.
- * CWMAX2: For AC_VI.
- * CWMAX3: For AC_VO.
+ * CWMAX0: For AC_VO.
+ * CWMAX1: For AC_VI.
+ * CWMAX2: For AC_BE.
+ * CWMAX3: For AC_BK.
*/
#define CWMAX_CSR 0x0408
#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
@@ -727,18 +727,18 @@ struct hw_pairwise_ta_entry {
#define CWMAX_CSR_CWMAX3 FIELD32(0x0000f000)

/*
- * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
- * AC0_TX_OP: For AC_BK, in unit of 32us.
- * AC1_TX_OP: For AC_BE, in unit of 32us.
+ * AC_TXOP_CSR0: AC_VO/AC_VI TXOP register.
+ * AC0_TX_OP: For AC_VO, in unit of 32us.
+ * AC1_TX_OP: For AC_VI, in unit of 32us.
*/
#define AC_TXOP_CSR0 0x040c
#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff)
#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000)

/*
- * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
- * AC2_TX_OP: For AC_VI, in unit of 32us.
- * AC3_TX_OP: For AC_VO, in unit of 32us.
+ * AC_TXOP_CSR1: AC_BE/AC_BK TXOP register.
+ * AC2_TX_OP: For AC_BE, in unit of 32us.
+ * AC3_TX_OP: For AC_BK, in unit of 32us.
*/
#define AC_TXOP_CSR1 0x0410
#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)
--
1.7.2.3


2010-12-17 13:58:12

by Alexander Khryukin

[permalink] [raw]
Subject: Re: wimaxd daemon bug

16.12.2010 17:10, Alexander Khryukin пишет:
> Good day.
> I have
> 1.MeeGo 1.1
> 2.Intel Corporation WiMAX/WiFi Link 6050 Series (rev 2c)
> 3.Wimax network that named 'Yota'
>
>
> wimaxcu scan wide
> WARNING: Wide scan may take upto 2 minutes...
> NSP : Yota
> ID : 21
> Signal : Excellent
> RSSI : -62 dBm
> CINR : 29 dB
> Network Type: Home Network
> Activated.
>
>
>
> Then i try to connect with Yota-network
>
> wimaxcu connect network 21
> Connecting to Yota Network...
> Connection successful
>
> [root@meego-desktop ~]# /usr/bin/wimaxd -d -i wmx0
> Enter Command:
> q - Quit AppSrv
> t - Trace ReInit (ReLoads Registry Values)
> u - uplink(Apdo uplink event
> h - Help
> d - Toggle driver messages to display - debug & internal only
>
>
> AppSrv is ready !
> Act_FullRestart!
> Act_DriverDeviceStatus - DRIVER_UP
> CTRL-EVENT-EAP-STARTED EAP authentication started
> Sending EapResponse. Data size: 25
> CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=13
> CTRL-EVENT-EAP-METHOD EAP vendor 0 method 13 (TLS) selected
> Sending EapResponse. Data size: 60
> Sending EapResponse. Data size: 60
> Sending EapResponse. Data size: 6
> Sending EapResponse. Data size: 6
> Sending EapResponse. Data size: 1310
> Sending EapResponse. Data size: 1144
> Sending EapResponse. Data size: 6
> CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
> CTRL-EVENT-EAP-STARTED EAP authentication started
> Sending EapResponse. Data size: 17
> CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=13
> CTRL-EVENT-EAP-METHOD EAP vendor 0 method 13 (TLS) selected
> Sending EapResponse. Data size: 60
> Sending EapResponse. Data size: 6
> Sending EapResponse. Data size: 6
> Sending EapResponse. Data size: 1310
> Sending EapResponse. Data size: 1144
> Sending EapResponse. Data size: 6
>
>
> Then i try to reconnect
>
> [root@meego-desktop ~]# wimaxcu connect network 21
> Current Preferred Profile is:
> ID : 21
> Name: Yota
> Connecting to Yota Network...
> Connection failure
>
>
> Next i try to
>
> wimaxll -i wmx0 reset
> and start daemon again
>
> /usr/bin/wimaxd -d -i wmx0
>
> Connect to network
>
> imaxcu connect network 21
> Current Preferred Profile is:
> ID : 21
> Name: Yota
> Connecting to Yota Network...
> Connection successful
>
>
> Wimaxd version wimax-1.5.1-35.13.i586.rpm
> from Inaky Perez-Gonzalez repo.
> http://download.meego.com/live/home:/inaky:/pegatron-idf-2010/Trunk/i586/
>
>
> uname -a
> Linux meego-desktop 2.6.36-1.9_mezon.12.1-netbook #1 SMP PREEMPT Wed Dec
> 15 20:01:48 MSK 2010 i686 i686 i386 GNU/Linux
>
>
>
> steps to reproduce:
> 1.Plug on Intel Corporation WiMAX/WiFi Link 6050 Series (rev 2c)
> 2.Install any version on wimaxd
> 3.wimaxcu connect any_network_id
> 4.wait about 2 minutes
> 5.connection dropped.
> 6.try connect again, and see "connection failure"
> 7.wimaxll -i wmx0 rese
> 8.connect to network again (it will be succeeded)
> 9.Proceed to step 4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>

Additional report.

[root@meego-desktop ~]# /usr/bin/wimaxd -d -i wmx0
Enter Command:
q - Quit AppSrv
t - Trace ReInit (ReLoads Registry Values)
u - uplink(Apdo uplink event
h - Help
d - Toggle driver messages to display - debug & internal only


AppSrv is ready !
Act_FullRestart!
Act_DriverDeviceStatus - DRIVER_UP




/var/log/wimax/wimaxd.log

http://pastebin.ca/2022059



And wait for 2 minutes

Now connection dropped in log nothing interesting not dropped

[root@meego-desktop ~]# wimaxcu connect network 21
Current Preferred Profile is:
ID : 21
Name: Yota
Connecting to Yota Network...
Connection failure


In log

http://pastebin.ca/2022057


2010-12-17 15:02:14

by Johannes Stezenbach

[permalink] [raw]
Subject: Re: [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use

On Fri, Dec 17, 2010 at 03:56:05AM -0800, Walter Goldens wrote:
>
> > Odd I have been testing this while stresstesting the card,
> > and either
> > unplugging, rmmod or ifdown, and I couldn't
> > reproduce any crashes. Has the stacktrace changed after
> > these patches?
>
> I can confirm when the rt2800usb is loaded and an rt3070 chip is connected to
> a network, running 'rmmod rt2800usb rt2x00lib rt2x00usb rt2800lib' causes
> immediate system hang (and hard-reset).

FWIW, I did not test this case. I only tested hot-unplug of the
USB device. However, I think usually when the network interface
is up the module use count should be incremented so that you
cannot unload the module.

Johannes

2010-12-13 11:40:18

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 06/17] rt2x00: Don't frequently reset beacon interval in AdHoc mode

From: Helmut Schaa <[email protected]>

Commit 0204464329c17ba6d293e1899f71223599a0e582 "Check for specific changed
flags when updating the erp config" changed the way in which a new beacon
interval gets handled. However, due to a bug in rt2800usb and rt2800pci the
beacon interval was reset during each scan, thus causing problems in AdHoc
mode.

Fix this by not cleaning up the beacon interval when killing the beacon queue
but just prevent the device from sending out beacons.

Reported-by: Wolfgang Kufner <[email protected]>
Signed-off-by: Helmut Schaa <[email protected]>
Acked-by: Gertjan van Wingerde <[email protected]>
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2400pci.c | 6 +++++-
drivers/net/wireless/rt2x00/rt2500pci.c | 6 +++++-
drivers/net/wireless/rt2x00/rt2500usb.c | 12 ++++++++++--
drivers/net/wireless/rt2x00/rt2800pci.c | 6 +++++-
drivers/net/wireless/rt2x00/rt2800usb.c | 12 ++++++++++--
drivers/net/wireless/rt2x00/rt61pci.c | 6 +++++-
drivers/net/wireless/rt2x00/rt73usb.c | 12 ++++++++++--
7 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 9ec6691..6278660 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1140,7 +1140,11 @@ static void rt2400pci_kill_tx_queue(struct data_queue *queue)
u32 reg;

if (queue->qid == QID_BEACON) {
- rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
} else {
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 3e7f203..ce9212f 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1294,7 +1294,11 @@ static void rt2500pci_kill_tx_queue(struct data_queue *queue)
u32 reg;

if (queue->qid == QID_BEACON) {
- rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
} else {
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 8152fec..bbfa671 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1205,8 +1205,16 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry)

static void rt2500usb_kill_tx_queue(struct data_queue *queue)
{
- if (queue->qid == QID_BEACON)
- rt2500usb_register_write(queue->rt2x00dev, TXRX_CSR19, 0);
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u16 reg;
+
+ if (queue->qid == QID_BEACON) {
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ }

rt2x00usb_kill_tx_queue(queue);
}
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 3a1468a..bea8352 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -588,7 +588,11 @@ static void rt2800pci_kill_tx_queue(struct data_queue *queue)
u32 reg;

if (queue->qid == QID_BEACON) {
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, 0);
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
return;
}

diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 042e47d..a150fcc 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -391,8 +391,16 @@ static void rt2800usb_work_txdone(struct work_struct *work)

static void rt2800usb_kill_tx_queue(struct data_queue *queue)
{
- if (queue->qid == QID_BEACON)
- rt2x00usb_register_write(queue->rt2x00dev, BCN_TIME_CFG, 0);
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ if (queue->qid == QID_BEACON) {
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ }

rt2x00usb_kill_tx_queue(queue);
}
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 6b09b01..6ad0c1c 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1944,7 +1944,11 @@ static void rt61pci_kill_tx_queue(struct data_queue *queue)
u32 reg;

if (queue->qid == QID_BEACON) {
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
return;
}

diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 6f04552..3934dad 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1581,8 +1581,16 @@ static int rt73usb_get_tx_data_len(struct queue_entry *entry)

static void rt73usb_kill_tx_queue(struct data_queue *queue)
{
- if (queue->qid == QID_BEACON)
- rt2x00usb_register_write(queue->rt2x00dev, TXRX_CSR9, 0);
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ if (queue->qid == QID_BEACON) {
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ }

rt2x00usb_kill_tx_queue(queue);
}
--
1.7.2.3


2010-12-16 14:17:11

by Alexander Khryukin

[permalink] [raw]
Subject: wimaxd daemon bug

Good day.
I have
1.MeeGo 1.1
2.Intel Corporation WiMAX/WiFi Link 6050 Series (rev 2c)
3.Wimax network that named 'Yota'


wimaxcu scan wide
WARNING: Wide scan may take upto 2 minutes...
NSP : Yota
ID : 21
Signal : Excellent
RSSI : -62 dBm
CINR : 29 dB
Network Type: Home Network
Activated.



Then i try to connect with Yota-network

wimaxcu connect network 21
Connecting to Yota Network...
Connection successful

[root@meego-desktop ~]# /usr/bin/wimaxd -d -i wmx0
Enter Command:
q - Quit AppSrv
t - Trace ReInit (ReLoads Registry Values)
u - uplink(Apdo uplink event
h - Help
d - Toggle driver messages to display - debug & internal only


AppSrv is ready !
Act_FullRestart!
Act_DriverDeviceStatus - DRIVER_UP
CTRL-EVENT-EAP-STARTED EAP authentication started
Sending EapResponse. Data size: 25
CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=13
CTRL-EVENT-EAP-METHOD EAP vendor 0 method 13 (TLS) selected
Sending EapResponse. Data size: 60
Sending EapResponse. Data size: 60
Sending EapResponse. Data size: 6
Sending EapResponse. Data size: 6
Sending EapResponse. Data size: 1310
Sending EapResponse. Data size: 1144
Sending EapResponse. Data size: 6
CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
CTRL-EVENT-EAP-STARTED EAP authentication started
Sending EapResponse. Data size: 17
CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=13
CTRL-EVENT-EAP-METHOD EAP vendor 0 method 13 (TLS) selected
Sending EapResponse. Data size: 60
Sending EapResponse. Data size: 6
Sending EapResponse. Data size: 6
Sending EapResponse. Data size: 1310
Sending EapResponse. Data size: 1144
Sending EapResponse. Data size: 6


Then i try to reconnect

[root@meego-desktop ~]# wimaxcu connect network 21
Current Preferred Profile is:
ID : 21
Name: Yota
Connecting to Yota Network...
Connection failure


Next i try to

wimaxll -i wmx0 reset
and start daemon again

/usr/bin/wimaxd -d -i wmx0

Connect to network

imaxcu connect network 21
Current Preferred Profile is:
ID : 21
Name: Yota
Connecting to Yota Network...
Connection successful


Wimaxd version wimax-1.5.1-35.13.i586.rpm
from Inaky Perez-Gonzalez repo.
http://download.meego.com/live/home:/inaky:/pegatron-idf-2010/Trunk/i586/


uname -a
Linux meego-desktop 2.6.36-1.9_mezon.12.1-netbook #1 SMP PREEMPT Wed Dec
15 20:01:48 MSK 2010 i686 i686 i386 GNU/Linux



steps to reproduce:
1.Plug on Intel Corporation WiMAX/WiFi Link 6050 Series (rev 2c)
2.Install any version on wimaxd
3.wimaxcu connect any_network_id
4.wait about 2 minutes
5.connection dropped.
6.try connect again, and see "connection failure"
7.wimaxll -i wmx0 rese
8.connect to network again (it will be succeeded)
9.Proceed to step 4


2010-12-15 16:38:44

by Ivo Van Doorn

[permalink] [raw]
Subject: Re: [PATCH 14/17] rt2x00: Fix WMM Queue naming

Hi,

>> >> The Queue names were incorrectly copied from the legacy drivers,
>> >> as a result the queue names were inversed to what was expected.
>> >>
>> >> This renames the queues using this mapping:
>> >> ? ? ? QID_AC_BK -> QID_AC_VO (priority 0)
>> >> ? ? ? QID_AC_BE -> QID_AC_VI (priority 1)
>> >> ? ? ? QID_AC_VI -> QID_AC_BE (priority 2)
>> >> ? ? ? QID_AC_VO -> QID_AC_BK (priority 3)
>> >>
>> >> Note that this was a naming problem only, which didn't affect
>> >> the assignment of frames to their respective queues.
>> >>
>> >> Signed-off-by: Ivo van Doorn <[email protected]>
>> >
>> > Ivo, due to the latest info from Ralink I'd say we should drop this patch
>> > and instead introduce a mac80211_to_rt2x00_qid mapper that maps from
>> > ieee80211_ac_numbers to data_queue_qid.
>> >
>> > This patch doesn't cause any harm, but we would have to revert it partly
>> > if we introduce the queue mapping as needed by the rt2x00 devices.
>>
>> I don't agree, this patch can safely be applied, since the mapping
>> is in the endpoint assignment, rather the register value usage,
>> I think the more optimal solution is fixing rt2x00usb_assign_endpoints.
>> In there it currently assigns endpoints assuming the first endpoint
>> is the highest priority, while we should be able to simply swap that
>> to invert the logic.
>
> Inverting is not enough since the first OUT EP (EP1) is AC_BE,
> while AC_BK (lowest priority) is EP2. ?This corresponds to the
> to the AC -> ACI mapping from 802.11 Table 7-36 in section
> "7.3.2.29 EDCA Parameter Set element". ?Probably the rationale
> is that ACI value 0 should be the "default" AC.

Ok, but that still means that we can apply this logic in the
assign_endpoints function.

Jay, can you confirm the endpoint assignment is the same
for rt73usb?

Thanks,

Ivo

2010-12-16 13:04:32

by Walter Goldens

[permalink] [raw]
Subject: Re: [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use

Even with the latest patches, rmmod'ing the rt2xXXX stuff causes a complete system freeze. Unless I bring down the interface first via 'ifconfig wlanX down', unloading the driver while operational equates OS hang and hard reset.

Walter.




2010-12-13 11:40:20

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 07/17] rt2x00: trivial: add missing \n on warnings

From: Johannes Stezenbach <[email protected]>

Signed-off-by: Johannes Stezenbach <[email protected]>
Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2800pci.c | 6 +++---
drivers/net/wireless/rt2x00/rt2800usb.c | 4 ++--
drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +-
drivers/net/wireless/rt2x00/rt2x00usb.c | 4 ++--
4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index bea8352..2b68009 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -686,7 +686,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* this tx status.
*/
WARNING(rt2x00dev, "Got TX status report with "
- "unexpected pid %u, dropping", qid);
+ "unexpected pid %u, dropping\n", qid);
break;
}

@@ -697,7 +697,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* processing here and drop the tx status
*/
WARNING(rt2x00dev, "Got TX status for an unavailable "
- "queue %u, dropping", qid);
+ "queue %u, dropping\n", qid);
break;
}

@@ -707,7 +707,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* and drop the tx status.
*/
WARNING(rt2x00dev, "Got TX status for an empty "
- "queue %u, dropping", qid);
+ "queue %u, dropping\n", qid);
break;
}

diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index a150fcc..1dfa59d 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -253,7 +253,7 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) {
WARNING(rt2x00dev, "TX HW queue 0 timed out,"
- " invoke forced kick");
+ " invoke forced kick\n");

rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40012);

@@ -269,7 +269,7 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) {
WARNING(rt2x00dev, "TX HW queue 1 timed out,"
- " invoke forced kick");
+ " invoke forced kick\n");

rt2800_register_write(rt2x00dev, PBF_CFG, 0xf4000a);

diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 829bf4b..7ad4b27 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -745,7 +745,7 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
}

if (!rt2x00queue_empty(queue))
- WARNING(rt2x00dev, "Failed to flush queue %d", queue->qid);
+ WARNING(rt2x00dev, "Failed to flush queue %d\n", queue->qid);
}

ieee80211_wake_queues(hw);
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 3a6c83e..608200e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -300,7 +300,7 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
unsigned short threshold = queue->threshold;

WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
- " invoke forced forced reset", queue->qid);
+ " invoke forced forced reset\n", queue->qid);

/*
* Temporarily disable the TX queue, this will force mac80211
@@ -335,7 +335,7 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
{
WARNING(queue->rt2x00dev, "TX queue %d status timed out,"
- " invoke forced tx handler", queue->qid);
+ " invoke forced tx handler\n", queue->qid);

ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work);
}
--
1.7.2.3


2010-12-13 12:36:50

by Ivo Van Doorn

[permalink] [raw]
Subject: Re: [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use

Hi,

> I have two issues to report regarding system hangs. The system would either freeze entirely, prompting me to hard-reset it, or it would freeze certain parts of the system like, no shell commands execution. These occurrences manifest themselves sporadically, when I'm switching between modes (ad-hoc, monitor etc.), also when I try to rmmod the rt2xxx stuff or when unplugging the USB chip. I have to "ifconcfig wlanx down" the device first in order to not hang my box. My question is, will this patch fix all of that, or only parts of it? Here's log I managed to dig out.

This patch, but also the queue refactoring patches in this series
should resolve all unplug and rmmod bugs.

> My second question pertains to the STA drivers - rt3070sta. It is not possible to switch between the rt2800usb and rt3070sta without having to unplug the device and plugging it back again followed by loading manually the desired driver.
> I'm not sure but I think this might have ?something to do withe voltage settings or the firmware. But it really is annoying to physically unplug the USB chip every time I switch between the two modules.
> Is it possible to enable switching between rt3070sta/rt2800usb without unplugging/plugging the USB chip?

It should be possible, but what are the exact problems that you encounter?
Is there a difference between going from rt3070sta to rt2800usb and vice versa?
(Please note that the rt2x00 project doesn't maintain the rt3070sta
driver in the staging directory).

Ivo

2010-12-13 12:27:49

by Walter Goldens

[permalink] [raw]
Subject: Re: [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use

> Signed-off-by: Johannes Stezenbach <[email protected]>
> Signed-off-by: Ivo van Doorn <[email protected]>
> ---
Hi.

I have two issues to report regarding system hangs. The system would either freeze entirely, prompting me to hard-reset it, or it would freeze certain parts of the system like, no shell commands execution. These occurrences manifest themselves sporadically, when I'm switching between modes (ad-hoc, monitor etc.), also when I try to rmmod the rt2xxx stuff or when unplugging the USB chip. I have to "ifconcfig wlanx down" the device first in order to not hang my box. My question is, will this patch fix all of that, or only parts of it? Here's log I managed to dig out.

[ 67.784831] phy0 -> rt2x00usb_vendor_request: Error - Vendor Request 0x07 failed for offset 0x1718 with error -19.
[ 67.789440] BUG: unable to handle kernel NULL pointer dereference at 00000004
[ 67.789455] IP: [<f833e536>] rt2x00usb_kick_tx_entry+0x16/0xc0 [rt2x00usb]
[ 67.789470] *pde = 7e56c067

[ 67.789564]
[ 67.789571] Pid: 21, comm: khubd Not tainted 2.6.35-23-generic #41-Ubuntu Latitude C840 /Latitude C840
[ 67.789577] EIP: 0060:[<f833e536>] EFLAGS: 00010282 CPU: 0
[ 67.789583] EIP is at rt2x00usb_kick_tx_entry+0x16/0xc0 [rt2x00usb]
[ 67.789588] EAX: 00000000 EBX: 00000000 ECX: 00000001 EDX: 00000000
[ 67.789592] ESI: f833e520 EDI: 00000001 EBP: f712bc7c ESP: f712bc68
[ 67.789597] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
[ 67.789602] Process khubd (pid: 21, ti=f712a000 task=f7130000 task.ti=f712a000)
[ 67.789606] Stack:
[ 67.789609] f712bc7c c05c94ef f20b603c f833e520 00000001 f712bcb4 f90c1825 c012ced8
[ 67.789620] <0> f712bc9c c05c94ef f712bc9c 00000286 00000004 00000000 f20b6048 00000001
[ 67.789631] <0> f20b6078 f20b603c f20cb040 f712bcc0 f833e7fe f833e520 f712bcdc f90c0198
[ 67.789644] Call Trace:
[ 67.789656] [<c05c94ef>] ? _raw_spin_lock_irqsave+0x2f/0x50
[ 67.789663] [<f833e520>] ? rt2x00usb_kick_tx_entry+0x0/0xc0 [rt2x00usb]
[ 67.789675] [<f90c1825>] ? rt2x00queue_for_each_entry+0xc5/0x120 [rt2x00lib]
[ 67.789685] [<c012ced8>] ? default_spin_lock_flags+0x8/0x10
[ 67.789691] [<c05c94ef>] ? _raw_spin_lock_irqsave+0x2f/0x50
[ 67.789699] [<f833e7fe>] ? rt2x00usb_kick_tx_queue+0x1e/0x20 [rt2x00usb]
[ 67.789706] [<f833e520>] ? rt2x00usb_kick_tx_entry+0x0/0xc0 [rt2x00usb]
[ 67.789714] [<f90c0198>] ? rt2x00mac_flush+0x48/0xd0 [rt2x00lib]
[ 67.789738] [<f9090272>] ? __ieee80211_recalc_idle+0x192/0x1a0 [mac80211]
[ 67.789753] [<f90902ac>] ? ieee80211_recalc_idle+0x2c/0x60 [mac80211]
[ 67.789766] [<f9086642>] ? __ieee80211_scan_completed_finish+0x32/0x90 [mac80211]
[ 67.789779] [<f9086721>] ? ieee80211_scan_cancel+0x81/0x90 [mac80211]
[ 67.789794] [<f9090e77>] ? ieee80211_do_stop+0x4a7/0x4d0 [mac80211]
[ 67.789804] [<c050e5a4>] ? dev_deactivate_queue+0x44/0x60
[ 67.789811] [<c05c9736>] ? _raw_spin_unlock_bh+0x16/0x20
[ 67.789817] [<c050e93e>] ? dev_deactivate+0x17e/0x190
[ 67.789832] [<f9090eb7>] ? ieee80211_stop+0x17/0x20 [mac80211]
[ 67.789841] [<c04f75e6>] ? __dev_close+0x46/0x80
[ 67.789849] [<c0352206>] ? kset_unregister+0x16/0x20
[ 67.789856] [<c04f7639>] ? dev_close+0x19/0x40
[ 67.789862] [<c04f76b5>] ? rollback_registered_many+0x55/0x1d0
[ 67.789868] [<c04f789a>] ? unregister_netdevice_queue+0x1a/0xc0
[ 67.789878] [<f90d7b4f>] ? rt2800_mcu_request+0x6f/0xd0 [rt2800lib]
[ 67.789885] [<c04f7844>] ? unregister_netdevice_many+0x14/0x50
[ 67.789900] [<f9090543>] ? ieee80211_remove_interfaces+0x83/0xc0 [mac80211]
[ 67.789906] [<c05c88b0>] ? down_write+0x10/0x30
[ 67.789917] [<f90820cb>] ? ieee80211_unregister_hw+0x4b/0x120 [mac80211]
[ 67.789925] [<f90bfa60>] ? rt2x00lib_remove_dev+0xd0/0xe0 [rt2x00lib]
[ 67.789932] [<f833e10f>] ? rt2x00usb_disconnect+0x2f/0x70 [rt2x00usb]
[ 67.789941] [<c0475e00>] ? usb_unbind_interface+0x40/0x150
[ 67.789949] [<c0400821>] ? __device_release_driver+0x51/0xb0
[ 67.789955] [<c0400945>] ? device_release_driver+0x25/0x40
[ 67.789961] [<c03ffbcb>] ? bus_remove_device+0x7b/0xa0
[ 67.789970] [<c03fdd17>] ? device_del+0xf7/0x180
[ 67.789977] [<c0472b25>] ? usb_disable_device+0x85/0x100
[ 67.789983] [<c046cf4e>] ? usb_disconnect+0xae/0x140
[ 67.789989] [<c046d4fa>] ? hub_port_connect_change+0x8a/0x8f0
[ 67.789995] [<c04736f3>] ? usb_control_msg+0xd3/0x130
[ 67.790003] [<c0460101>] ? ppp_unattached_ioctl+0x1a1/0x270
[ 67.790009] [<c046ecd0>] ? hub_events+0x2b0/0x4f0
[ 67.790019] [<c016601f>] ? finish_wait+0x4f/0x70
[ 67.790024] [<c046ef4a>] ? hub_thread+0x3a/0x140
[ 67.790030] [<c0165eb0>] ? autoremove_wake_function+0x0/0x50
[ 67.790036] [<c046ef10>] ? hub_thread+0x0/0x140
[ 67.790042] [<c0165a84>] ? kthread+0x74/0x80
[ 67.790047] [<c0165a10>] ? kthread+0x0/0x80
[ 67.790055] [<c010363e>] ? kernel_thread_helper+0x6/0x10
[ 67.790058] Code: d8 e8 6f 0d d8 00 eb 8b 8d b6 00 00 00 00 8d bc 27 00 00 00 00 55 89 e5 83 ec 14 89 5d f4 89 75 f8 89 7d fc 0f 1f 44 00 00 89 c3 <8b> 40 04 8b 73 10 8b 00 8b 10 8b 3a 3e 0f ba 33 02 19 d2 85 d2
[ 67.790119] EIP: [<f833e536>] rt2x00usb_kick_tx_entry+0x16/0xc0 [rt2x00usb] SS:ESP 0068:f712bc68
[ 67.790128] CR2: 0000000000000004
[ 67.790133] ---[ end trace 81dd02b06472de40 ]---

My second question pertains to the STA drivers - rt3070sta. It is not possible to switch between the rt2800usb and rt3070sta without having to unplug the device and plugging it back again followed by loading manually the desired driver.
I'm not sure but I think this might have something to do withe voltage settings or the firmware. But it really is annoying to physically unplug the USB chip every time I switch between the two modules.
Is it possible to enable switching between rt3070sta/rt2800usb without unplugging/plugging the USB chip?

Walter




2010-12-17 11:56:10

by Walter Goldens

[permalink] [raw]
Subject: Re: [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use


> Odd I have been testing this while stresstesting the card,
> and either
> unplugging, rmmod or ifdown, and I couldn't
> reproduce any crashes. Has the stacktrace changed after
> these patches?

Hi.

I can confirm when the rt2800usb is loaded and an rt3070 chip is connected to a network, running 'rmmod rt2800usb rt2x00lib rt2x00usb rt2800lib' causes immediate system hang (and hard-reset).

I was not able to retrieve any relevant error logs.

Walter




2010-12-13 11:40:27

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 11/17] rt2x00: Add "flush" queue command

Add a new command to the queue handlers: "flush",
this moves the flush() callback from mac80211
into rt2x00queue and adds support for flushing
the RX queue as well.

Signed-off-by: Ivo van Doorn <[email protected]>
Acked-by: Helmut Schaa <[email protected]>
---
drivers/net/wireless/rt2x00/rt2500usb.c | 3 +-
drivers/net/wireless/rt2x00/rt2800usb.c | 3 +-
drivers/net/wireless/rt2x00/rt2x00.h | 21 +++++++
drivers/net/wireless/rt2x00/rt2x00dev.c | 1 +
drivers/net/wireless/rt2x00/rt2x00mac.c | 32 +----------
drivers/net/wireless/rt2x00/rt2x00queue.c | 85 +++++++++++++++++++++++++++++
drivers/net/wireless/rt2x00/rt2x00usb.c | 70 ++++++++++++++++--------
drivers/net/wireless/rt2x00/rt2x00usb.h | 4 +-
drivers/net/wireless/rt2x00/rt73usb.c | 3 +-
9 files changed, 161 insertions(+), 61 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index a56b38f..6b3b1de4 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -785,8 +785,6 @@ static void rt2500usb_stop_queue(struct data_queue *queue)
default:
break;
}
-
- rt2x00usb_stop_queue(queue);
}

/*
@@ -1842,6 +1840,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.start_queue = rt2500usb_start_queue,
.kick_queue = rt2x00usb_kick_queue,
.stop_queue = rt2500usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt2500usb_write_tx_desc,
.write_beacon = rt2500usb_write_beacon,
.get_tx_data_len = rt2500usb_get_tx_data_len,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 60b5503..3e0205d 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -96,8 +96,6 @@ static void rt2800usb_stop_queue(struct data_queue *queue)
default:
break;
}
-
- rt2x00usb_stop_queue(queue);
}

/*
@@ -623,6 +621,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.start_queue = rt2800usb_start_queue,
.kick_queue = rt2x00usb_kick_queue,
.stop_queue = rt2800usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt2800usb_write_tx_desc,
.write_tx_data = rt2800usb_write_tx_data,
.write_beacon = rt2800_write_beacon,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 511ca91..520e736 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -575,6 +575,7 @@ struct rt2x00lib_ops {
void (*start_queue) (struct data_queue *queue);
void (*kick_queue) (struct data_queue *queue);
void (*stop_queue) (struct data_queue *queue);
+ void (*flush_queue) (struct data_queue *queue);

/*
* TX control handlers
@@ -1108,6 +1109,16 @@ void rt2x00queue_start_queue(struct data_queue *queue);
void rt2x00queue_stop_queue(struct data_queue *queue);

/**
+ * rt2x00queue_flush_queue - Flush a data queue
+ * @queue: Pointer to &struct data_queue.
+ * @drop: True to drop all pending frames.
+ *
+ * This function will flush the queue. After this call
+ * the queue is guarenteed to be empty.
+ */
+void rt2x00queue_flush_queue(struct data_queue *queue, bool drop);
+
+/**
* rt2x00queue_start_queues - Start all data queues
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
@@ -1124,6 +1135,16 @@ void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev);
*/
void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev);

+/**
+ * rt2x00queue_flush_queues - Flush all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @drop: True to drop all pending frames.
+ *
+ * This function will loop through all available queues to flush
+ * any pending frames.
+ */
+void rt2x00queue_flush_queues(struct rt2x00_dev *rt2x00dev, bool drop);
+
/*
* Debugfs handlers.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index fbc98dd..01c8415 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -94,6 +94,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
*/
rt2x00link_stop_tuner(rt2x00dev);
rt2x00queue_stop_queues(rt2x00dev);
+ rt2x00queue_flush_queues(rt2x00dev, true);

/*
* Disable radio.
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index c4abb20..4cac7ad 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -718,36 +718,8 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
- unsigned int i = 0;

- ieee80211_stop_queues(hw);
-
- /*
- * Run over all queues to kick them, this will force
- * any pending frames to be transmitted.
- */
- tx_queue_for_each(rt2x00dev, queue) {
- rt2x00dev->ops->lib->kick_queue(queue);
- }
-
- /**
- * All queues have been kicked, now wait for each queue
- * to become empty. With a bit of luck, we only have to wait
- * for the first queue to become empty, because while waiting
- * for the that queue, the other queues will have transmitted
- * all their frames as well (since they were already kicked).
- */
- tx_queue_for_each(rt2x00dev, queue) {
- for (i = 0; i < 10; i++) {
- if (rt2x00queue_empty(queue))
- break;
- msleep(100);
- }
-
- if (!rt2x00queue_empty(queue))
- WARNING(rt2x00dev, "Failed to flush queue %d\n", queue->qid);
- }
-
- ieee80211_wake_queues(hw);
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_flush_queue(queue, drop);
}
EXPORT_SYMBOL_GPL(rt2x00mac_flush);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 558965f..313a8fa 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -780,6 +780,12 @@ void rt2x00queue_unpause_queue(struct data_queue *queue)
*/
ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
break;
+ case QID_RX:
+ /*
+ * For RX we need to kick the queue now in order to
+ * receive frames.
+ */
+ queue->rt2x00dev->ops->lib->kick_queue(queue);
default:
break;
}
@@ -823,6 +829,74 @@ void rt2x00queue_stop_queue(struct data_queue *queue)
}
EXPORT_SYMBOL_GPL(rt2x00queue_stop_queue);

+void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
+{
+ unsigned int i;
+ bool started;
+ bool tx_queue =
+ (queue->qid == QID_AC_BE) ||
+ (queue->qid == QID_AC_BK) ||
+ (queue->qid == QID_AC_VI) ||
+ (queue->qid == QID_AC_VO);
+
+ mutex_lock(&queue->status_lock);
+
+ /*
+ * If the queue has been started, we must stop it temporarily
+ * to prevent any new frames to be queued on the device. If
+ * we are not dropping the pending frames, the queue must
+ * only be stopped in the software and not the hardware,
+ * otherwise the queue will never become empty on its own.
+ */
+ started = test_bit(QUEUE_STARTED, &queue->flags);
+ if (started) {
+ /*
+ * Pause the queue
+ */
+ rt2x00queue_pause_queue(queue);
+
+ /*
+ * If we are not supposed to drop any pending
+ * frames, this means we must force a start (=kick)
+ * to the queue to make sure the hardware will
+ * start transmitting.
+ */
+ if (!drop && tx_queue)
+ queue->rt2x00dev->ops->lib->kick_queue(queue);
+ }
+
+ /*
+ * Check if driver supports flushing, we can only guarentee
+ * full support for flushing if the driver is able
+ * to cancel all pending frames (drop = true).
+ */
+ if (drop && queue->rt2x00dev->ops->lib->flush_queue)
+ queue->rt2x00dev->ops->lib->flush_queue(queue);
+
+ /*
+ * When we don't want to drop any frames, or when
+ * the driver doesn't fully flush the queue correcly,
+ * we must wait for the queue to become empty.
+ */
+ for (i = 0; !rt2x00queue_empty(queue) && i < 100; i++)
+ msleep(10);
+
+ /*
+ * The queue flush has failed...
+ */
+ if (unlikely(!rt2x00queue_empty(queue)))
+ WARNING(queue->rt2x00dev, "Queue %d failed to flush", queue->qid);
+
+ /*
+ * Restore the queue to the previous status
+ */
+ if (started)
+ rt2x00queue_unpause_queue(queue);
+
+ mutex_unlock(&queue->status_lock);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_flush_queue);
+
void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
@@ -857,6 +931,17 @@ void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2x00queue_stop_queues);

+void rt2x00queue_flush_queues(struct rt2x00_dev *rt2x00dev, bool drop)
+{
+ struct data_queue *queue;
+
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_flush_queue(queue, drop);
+
+ rt2x00queue_flush_queue(rt2x00dev->rx, drop);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_flush_queues);
+
static void rt2x00queue_reset(struct data_queue *queue)
{
unsigned long irqflags;
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index fca29ae..cd80eec 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -366,7 +366,7 @@ void rt2x00usb_kick_queue(struct data_queue *queue)
}
EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue);

-static void rt2x00usb_kill_entry(struct queue_entry *entry)
+static void rt2x00usb_flush_entry(struct queue_entry *entry)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
@@ -385,37 +385,61 @@ static void rt2x00usb_kill_entry(struct queue_entry *entry)
usb_kill_urb(bcn_priv->guardian_urb);
}

-void rt2x00usb_stop_queue(struct data_queue *queue)
+void rt2x00usb_flush_queue(struct data_queue *queue)
{
+ struct work_struct *completion;
+ unsigned int i;
+
rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
- rt2x00usb_kill_entry);
+ rt2x00usb_flush_entry);
+
+ /*
+ * Obtain the queue completion handler
+ */
+ switch (queue->qid) {
+ case QID_AC_BE:
+ case QID_AC_BK:
+ case QID_AC_VI:
+ case QID_AC_VO:
+ completion = &queue->rt2x00dev->txdone_work;
+ break;
+ case QID_RX:
+ completion = &queue->rt2x00dev->rxdone_work;
+ break;
+ default:
+ return;
+ }
+
+ for (i = 0; i < 20; i++) {
+ /*
+ * Check if the driver is already done, otherwise we
+ * have to sleep a little while to give the driver/hw
+ * the oppurtunity to complete interrupt process itself.
+ */
+ if (rt2x00queue_empty(queue))
+ break;
+
+ /*
+ * Schedule the completion handler manually, when this
+ * worker function runs, it should cleanup the queue.
+ */
+ ieee80211_queue_work(queue->rt2x00dev->hw, completion);
+
+ /*
+ * Wait for a little while to give the driver
+ * the oppurtunity to recover itself.
+ */
+ msleep(10);
+ }
}
-EXPORT_SYMBOL_GPL(rt2x00usb_stop_queue);
+EXPORT_SYMBOL_GPL(rt2x00usb_flush_queue);

static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
-
WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
" invoke forced forced reset\n", queue->qid);

- /*
- * Temporarily disable the TX queue, this will force mac80211
- * to use the other queues until this queue has been restored.
- */
- rt2x00queue_stop_queue(queue);
-
- /*
- * In case that a driver has overriden the txdone_work
- * function, we invoke the TX done through there.
- */
- rt2x00dev->txdone_work.func(&rt2x00dev->txdone_work);
-
- /*
- * The queue has been reset, and mac80211 is allowed to use the
- * queue again.
- */
- rt2x00queue_start_queue(queue);
+ rt2x00queue_flush_queue(queue, true);
}

static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 05a5424..6aaf51f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -387,13 +387,13 @@ struct queue_entry_priv_usb_bcn {
void rt2x00usb_kick_queue(struct data_queue *queue);

/**
- * rt2x00usb_stop_queue - Stop data queue
+ * rt2x00usb_flush_queue - Flush data queue
* @queue: Data queue to stop
*
* This will walk through all entries of the queue and kill all
* URB's which were send to the device.
*/
-void rt2x00usb_stop_queue(struct data_queue *queue);
+void rt2x00usb_flush_queue(struct data_queue *queue);

/**
* rt2x00usb_watchdog - Watchdog for USB communication
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index f55e74e..0b3959b 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1077,8 +1077,6 @@ static void rt73usb_stop_queue(struct data_queue *queue)
default:
break;
}
-
- rt2x00usb_stop_queue(queue);
}

/*
@@ -2309,6 +2307,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.start_queue = rt73usb_start_queue,
.kick_queue = rt2x00usb_kick_queue,
.stop_queue = rt73usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt73usb_write_tx_desc,
.write_beacon = rt73usb_write_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,
--
1.7.2.3