rt2x00: Reduce tx status reading timeout
PATCH 1/6 rt2x00: Reduce tx status reading timeout
When no TX status was available, the default timeout of 20ms is a bit high. The frame is highly likely already send out, so the TX status should be available within only a few milliseconds.
--- drivers/net/wireless/rt2x00/rt2800usb.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/rt2x00/rt2800usb.c +2 -2
@@ -134,7 +134,7 @@ static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, }else if (!kfifo_is_empty (&rt2x00dev->txstatus_fifo)) {queue_work (rt2x00dev->workqueue, &rt2x00dev->txdone_work); }else if (rt2800usb_txstatus_pending (rt2x00dev)) { -mod_timer (&rt2x00dev->txstatus_timer, jiffies +msecs_to_jiffies (20 )); +mod_timer (&rt2x00dev->txstatus_timer, jiffies +msecs_to_jiffies (2 )); } }
@@ -493,7 +493,7 @@ static void rt2800usb_work_txdone(struct work_struct *work)* also delayed -> use a timer to retrieve it. */ if (rt2800usb_txstatus_pending (rt2x00dev)) -mod_timer (&rt2x00dev->txstatus_timer, jiffies +msecs_to_jiffies (20 )); +mod_timer (&rt2x00dev->txstatus_timer, jiffies +msecs_to_jiffies (2 )); }/*
Signature · 1 line
1.7.2.3
PATCH 2/6 rt2x00: Optimize TX_STA_FIFO register reading
Add recycling functionality to rt2x00usb_register_read_async. When the callback function returns true, resubmit the urb to read the register again.
This optimizes the rt2800usb driver when multiple TX status reports are pending in the register, because now we don't need to allocate the rt2x00_async_read_data and urb structure each time.
--- drivers/net/wireless/rt2x00/rt2800usb.c | 9 +++++---- drivers/net/wireless/rt2x00/rt2x00usb.c | 11 +++++++---- drivers/net/wireless/rt2x00/rt2x00usb.h | 4 +++- 3 files changed, 15 insertions(+), 9 deletions(-)
drivers/net/wireless/rt2x00/rt2800usb.c +5 -4
@@ -114,12 +114,12 @@ static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev)return false; } -static void rt2800usb_tx_sta_fifo_read_completed (struct rt2x00_dev *rt2x00dev, +static bool rt2800usb_tx_sta_fifo_read_completed (struct rt2x00_dev *rt2x00dev,int urb_status,u32 tx_status) {if (urb_status) {WARNING (rt2x00dev,"rt2x00usb_register_read_async failed: %d\n" , urb_status); -return ; +return false; }/* try to read all TX_STA_FIFO entries before scheduling txdone_work */
@@ -129,13 +129,14 @@ static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, "drop tx status report.\n");queue_work (rt2x00dev->workqueue, &rt2x00dev->txdone_work); }else -rt2x00usb_register_read_async (rt2x00dev,TX_STA_FIFO , - rt2800usb_tx_sta_fifo_read_completed); +return true; }else if (!kfifo_is_empty (&rt2x00dev->txstatus_fifo)) {queue_work (rt2x00dev->workqueue, &rt2x00dev->txdone_work); }else if (rt2800usb_txstatus_pending (rt2x00dev)) {mod_timer (&rt2x00dev->txstatus_timer, jiffies +msecs_to_jiffies (2 )); } + +return false; }static void rt2800usb_tx_dma_done (struct queue_entry *entry)
drivers/net/wireless/rt2x00/rt2x00usb.c +7 -4
@@ -170,19 +170,22 @@ struct rt2x00_async_read_data {__le32 reg;struct usb_ctrlrequest cr;struct rt2x00_dev *rt2x00dev; -void (*callback)(struct rt2x00_dev *,int ,u32 ); +bool (*callback)(struct rt2x00_dev *,int ,u32 ); };static void rt2x00usb_register_read_async_cb (struct urb *urb) {struct rt2x00_async_read_data *rd = urb->context; - rd->callback (rd->rt2x00dev, urb->status,le32_to_cpu (rd->reg)); -kfree (urb->context); +if (rd->callback (rd->rt2x00dev, urb->status,le32_to_cpu (rd->reg))) { +if (usb_submit_urb (urb,GFP_ATOMIC ) <0 ) +kfree (rd); + }else +kfree (rd); }void rt2x00usb_register_read_async (struct rt2x00_dev *rt2x00dev,const unsigned int offset, -void (*callback)(struct rt2x00_dev *,int ,u32 )) +bool (*callback)(struct rt2x00_dev *,int ,u32 )) {struct usb_device *usb_dev =to_usb_device_intf (rt2x00dev->dev);struct urb *urb;
drivers/net/wireless/rt2x00/rt2x00usb.h +3 -1
@@ -349,10 +349,12 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,* be called from atomic context. The callback will be called * when the URB completes. Otherwise the function is similar * to rt2x00usb_register_read(). +* When the callback function returns false, the memory will be cleaned up, +* when it returns true, the urb will be fired again. */ void rt2x00usb_register_read_async (struct rt2x00_dev *rt2x00dev,const unsigned int offset, -void (*callback)(struct rt2x00_dev *,int ,u32 )); +bool (*callback)(struct rt2x00_dev *,int ,u32 ));/* * Radio handlers
Signature · 1 line
1.7.2.3
PATCH 3/6 rt2x00: Fix optimize register access for rt2800pci
The patch
rt2x00: Optimize register access in rt2800pci
from Helmut Schaa missed one register call, namely the rt2800_register_multiwrite which should be changed to rt2x00pci_register_multiwrite.
--- drivers/net/wireless/rt2x00/rt2800pci.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/rt2x00/rt2800pci.c +2 -2
@@ -302,8 +302,8 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,/* * Write firmware to device. */ -rt2800_register_multiwrite (rt2x00dev,FIRMWARE_IMAGE_BASE , - data, len); +rt2x00pci_register_multiwrite (rt2x00dev,FIRMWARE_IMAGE_BASE , + data, len);rt2x00pci_register_write (rt2x00dev,PBF_SYS_CTRL ,0x00000 );rt2x00pci_register_write (rt2x00dev,PBF_SYS_CTRL ,0x00001 );
Signature · 1 line
1.7.2.3
PATCH 4/6 rt2x00: Streamline rt2800 eeprom initialisations.
From: Gertjan van Wingerde <[email protected]>
In rt2800lib.c the rt2800_init_eeprom function the same eeprom words were read multiple times, due to inefficient ordering of the eeprom checks.
Reorder the checks so that each EEPROM word only has to be read once.
--- drivers/net/wireless/rt2x00/rt2800lib.c | 18 ++++++++---------- 1 files changed, 8 insertions(+), 10 deletions(-)
drivers/net/wireless/rt2x00/rt2800lib.c +8 -10
@@ -3727,16 +3727,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) }/* -* Read frequency offset and RF programming sequence. +* Determine external LNA informations. */ -rt2x00_eeprom_read (rt2x00dev,EEPROM_FREQ , &eeprom); - rt2x00dev->freq_offset =rt2x00_get_field16 (eeprom,EEPROM_FREQ_OFFSET ); - -/* -* Read external LNA informations. -*/ -rt2x00_eeprom_read (rt2x00dev,EEPROM_NIC_CONF1 , &eeprom); -if (rt2x00_get_field16 (eeprom,EEPROM_NIC_CONF1_EXTERNAL_LNA_5G ))__set_bit (CAPABILITY_EXTERNAL_LNA_A , &rt2x00dev->cap_flags);if (rt2x00_get_field16 (eeprom,EEPROM_NIC_CONF1_EXTERNAL_LNA_2G ))
@@ -3749,6 +3741,12 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)__set_bit (CAPABILITY_HW_BUTTON , &rt2x00dev->cap_flags);/* +* Read frequency offset and RF programming sequence. +*/ +rt2x00_eeprom_read (rt2x00dev,EEPROM_FREQ , &eeprom); + rt2x00dev->freq_offset =rt2x00_get_field16 (eeprom,EEPROM_FREQ_OFFSET ); + +/* * Store led settings, for correct led behaviour. */ #ifdef CONFIG_RT2X00_LIB_LEDS
@@ -3756,7 +3754,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)rt2800_init_led (rt2x00dev, &rt2x00dev->led_assoc,LED_TYPE_ASSOC );rt2800_init_led (rt2x00dev, &rt2x00dev->led_qual,LED_TYPE_QUALITY ); -rt2x00_eeprom_read (rt2x00dev,EEPROM_FREQ , &rt2x00dev->led_mcu_reg); + rt2x00dev->led_mcu_reg = eeprom;#endif /* CONFIG_RT2X00_LIB_LEDS */ /*
Signature · 1 line
1.7.2.3
PATCH 5/6 rt2x00: Introduce capability flag for Bluetooth co-existence.
From: Gertjan van Wingerde <[email protected]>
Use flag instead of re-reading the eeprom every time.
--- drivers/net/wireless/rt2x00/rt2800lib.c | 13 ++++++++----- drivers/net/wireless/rt2x00/rt2x00.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-)
drivers/net/wireless/rt2x00/rt2800lib.c +8 -5
@@ -1640,7 +1640,6 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, struct channel_info *info) {u8 rfcsr; -u16 eeprom;rt2800_rfcsr_write (rt2x00dev,8 , rf->rf1);rt2800_rfcsr_write (rt2x00dev,9 , rf->rf3);
@@ -1670,11 +1669,10 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,rt2x00_set_field8 (&rfcsr,RFCSR17_CODE , rt2x00dev->freq_offset);rt2800_rfcsr_write (rt2x00dev,17 , rfcsr); -rt2x00_eeprom_read (rt2x00dev,EEPROM_NIC_CONF1 , &eeprom);if (rf->channel <=14 ) {int idx = rf->channel-1 ; -if (rt2x00_get_field16 (eeprom,EEPROM_NIC_CONF1_BT_COEXIST )) { +if (test_bit (CAPABILITY_BT_COEXIST , &rt2x00dev->cap_flags)) {if (rt2x00_rt_rev_gte (rt2x00dev,RT5390 ,REV_RT5390F )) {/* r55/r59 value array of channel 1~14 */ static const char r55_bt_rev[] = {0x83, 0x83,
@@ -2917,8 +2915,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) ant = (div_mode ==3 ) ?1 :0 ;/* check if this is a Bluetooth combo card */ -rt2x00_eeprom_read (rt2x00dev,EEPROM_NIC_CONF1 , &eeprom); -if (rt2x00_get_field16 (eeprom,EEPROM_NIC_CONF1_BT_COEXIST )) { +if (test_bit (CAPABILITY_BT_COEXIST , &rt2x00dev->cap_flags)) {u32 reg;rt2800_register_read (rt2x00dev,GPIO_CTRL_CFG , ®);
@@ -3741,6 +3738,12 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)__set_bit (CAPABILITY_HW_BUTTON , &rt2x00dev->cap_flags);/* +* Detect if this device has Bluetooth co-existence. +*/ +if (rt2x00_get_field16 (eeprom,EEPROM_NIC_CONF1_BT_COEXIST )) +__set_bit (CAPABILITY_BT_COEXIST , &rt2x00dev->cap_flags); + +/* * Read frequency offset and RF programming sequence. */ rt2x00_eeprom_read (rt2x00dev,EEPROM_FREQ , &eeprom);
drivers/net/wireless/rt2x00/rt2x00.h +1 -0
@@ -697,6 +697,7 @@ enum rt2x00_capability_flags {CAPABILITY_EXTERNAL_LNA_A ,CAPABILITY_EXTERNAL_LNA_BG ,CAPABILITY_DOUBLE_ANTENNA , + CAPABILITY_BT_COEXIST, };/*
Signature · 1 line
1.7.2.3
PATCH 6/6 rt2x00: Add autowake support for USB hardware
The USB drivers don't support automatically waking up when in powersaving mode, add a work object which will wakeup the device in time to receive the next beacon. Based on that beacon, we either go back into powersaving mode, or we remain awake to receive the buffered frames for our station.
Some part of the code, especially rt2x00lib_find_ie and rt2x00lib_rxdone_check_ps are inspired on the code from carl9170.
--- drivers/net/wireless/rt2x00/rt2500usb.c | 1 + drivers/net/wireless/rt2x00/rt2800usb.c | 1 + drivers/net/wireless/rt2x00/rt2x00.h | 17 +++++ drivers/net/wireless/rt2x00/rt2x00config.c | 31 ++++++++++ drivers/net/wireless/rt2x00/rt2x00dev.c | 88 ++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt73usb.c | 1 + 6 files changed, 139 insertions(+), 0 deletions(-)
drivers/net/wireless/rt2x00/rt2500usb.c +1 -0
@@ -1797,6 +1797,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)__set_bit (REQUIRE_COPY_IV , &rt2x00dev->cap_flags); }__set_bit (REQUIRE_SW_SEQNO , &rt2x00dev->cap_flags); +__set_bit (REQUIRE_PS_AUTOWAKE , &rt2x00dev->cap_flags);/* * Set the rssi offset.
drivers/net/wireless/rt2x00/rt2800usb.c +1 -0
@@ -634,6 +634,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)__set_bit (CAPABILITY_LINK_TUNING , &rt2x00dev->cap_flags);__set_bit (REQUIRE_HT_TX_DESC , &rt2x00dev->cap_flags);__set_bit (REQUIRE_TXSTATUS_FIFO , &rt2x00dev->cap_flags); +__set_bit (REQUIRE_PS_AUTOWAKE , &rt2x00dev->cap_flags); setup_timer(&rt2x00dev->txstatus_timer, rt2800usb_tx_sta_fifo_timeout,
drivers/net/wireless/rt2x00/rt2x00.h +17 -0
@@ -662,6 +662,7 @@ enum rt2x00_state_flags {* Driver configuration */ CONFIG_CHANNEL_HT40 , + CONFIG_POWERSAVING, };/*
@@ -681,6 +682,7 @@ enum rt2x00_capability_flags {REQUIRE_TASKLET_CONTEXT ,REQUIRE_SW_SEQNO ,REQUIRE_HT_TX_DESC , + REQUIRE_PS_AUTOWAKE,/* * Capabilities
@@ -875,10 +877,20 @@ struct rt2x00_dev {u8 calibration[2 ];/* +* Association id. +*/ +u16 aid; + +/* * Beacon interval. */ u16 beacon_int; +/** +* Timestamp of last received beacon +*/ +unsigned long last_beacon; +/* * Low level statistics which will have * to be kept up to date while device is running.
@@ -907,6 +919,11 @@ struct rt2x00_dev {struct work_struct txdone_work;/* +* Powersaving work +*/ +struct delayed_work autowakeup_work; + +/* * Data queue arrays for RX, TX, Beacon and ATIM. */ unsigned int data_queues;
drivers/net/wireless/rt2x00/rt2x00config.c +31 -0
@@ -100,6 +100,10 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.basic_rates = bss_conf->basic_rates; erp.beacon_int = bss_conf->beacon_int; +/* Update the AID, this is needed for dynamic PS support */ + rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid :0 ; + rt2x00dev->last_beacon = bss_conf->timestamp; +/* Update global beacon interval time, this is needed for PS support */ rt2x00dev->beacon_int = bss_conf->beacon_int;
@@ -204,6 +208,9 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, {struct rt2x00lib_conf libconf;u16 hw_value; +u16 autowake_timeout; +u16 beacon_int; +u16 beacon_diff;memset (&libconf,0 ,sizeof (libconf));
@@ -227,6 +234,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, sizeof(libconf.channel)); } +if (test_bit (REQUIRE_PS_AUTOWAKE , &rt2x00dev->cap_flags) && + (ieee80211_flags &IEEE80211_CONF_CHANGE_PS )) +cancel_delayed_work_sync (&rt2x00dev->autowakeup_work); +/* * Start configuration. */
@@ -239,6 +250,26 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,if (ieee80211_flags &IEEE80211_CONF_CHANGE_CHANNEL )rt2x00link_reset_tuner (rt2x00dev, false); +if (test_bit (REQUIRE_PS_AUTOWAKE , &rt2x00dev->cap_flags) && + (ieee80211_flags &IEEE80211_CONF_CHANGE_PS ) && + (conf->flags &IEEE80211_CONF_PS )) { + beacon_diff = (long )jiffies - (long )rt2x00dev->last_beacon; + beacon_int =msecs_to_jiffies (rt2x00dev->beacon_int); + +if (beacon_diff > beacon_int) + beacon_diff =0 ; + + autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff; +queue_delayed_work (rt2x00dev->workqueue, + &rt2x00dev->autowakeup_work, + autowake_timeout -15 ); + } + +if (conf->flags &IEEE80211_CONF_PS ) +set_bit (CONFIG_POWERSAVING , &rt2x00dev->flags); +else +clear_bit (CONFIG_POWERSAVING , &rt2x00dev->flags); + rt2x00dev->curr_band = conf->channel->band; rt2x00dev->curr_freq = conf->channel->center_freq; rt2x00dev->tx_power = conf->power_level;
drivers/net/wireless/rt2x00/rt2x00dev.c +88 -0
112 lines not on this page · raw message
drivers/net/wireless/rt2x00/rt73usb.c +1 -0
@@ -2209,6 +2209,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)if (!modparam_nohwcrypt)__set_bit (CAPABILITY_HW_CRYPTO , &rt2x00dev->cap_flags);__set_bit (CAPABILITY_LINK_TUNING , &rt2x00dev->cap_flags); +__set_bit (REQUIRE_PS_AUTOWAKE , &rt2x00dev->cap_flags);/* * Set the rssi offset.
Signature · 1 line
1.7.2.3