diff options
author | John W. Linville <linville@tuxdriver.com> | 2011-05-05 13:32:35 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-05-05 13:32:35 -0400 |
commit | a70171dce9cd44cb06c7d299eba9fa87a8933045 (patch) | |
tree | 5425df5f33fadc617c7dec99578d06f0d933578e /drivers/net/wireless/rt2x00 | |
parent | 5a412ad7f4c95bb5b756aa12b52646e857e7c75d (diff) | |
parent | eaef6a93bd52a2cc47b9fce201310010707afdb4 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts:
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/rtlwifi/pci.c
net/bluetooth/l2cap_sock.c
Diffstat (limited to 'drivers/net/wireless/rt2x00')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500usb.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800lib.c | 31 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800pci.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800usb.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00.h | 18 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00config.c | 31 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 88 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00usb.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00usb.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt73usb.c | 1 |
10 files changed, 175 insertions, 28 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index b21f81231a09..15237c275486 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -1797,6 +1797,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
1797 | __set_bit(REQUIRE_COPY_IV, &rt2x00dev->cap_flags); | 1797 | __set_bit(REQUIRE_COPY_IV, &rt2x00dev->cap_flags); |
1798 | } | 1798 | } |
1799 | __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); | 1799 | __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); |
1800 | __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); | ||
1800 | 1801 | ||
1801 | /* | 1802 | /* |
1802 | * Set the rssi offset. | 1803 | * Set the rssi offset. |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 5cd096e2ae36..790afd3ed946 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -1640,7 +1640,6 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, | |||
1640 | struct channel_info *info) | 1640 | struct channel_info *info) |
1641 | { | 1641 | { |
1642 | u8 rfcsr; | 1642 | u8 rfcsr; |
1643 | u16 eeprom; | ||
1644 | 1643 | ||
1645 | rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); | 1644 | rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); |
1646 | rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); | 1645 | rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); |
@@ -1670,11 +1669,10 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, | |||
1670 | rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); | 1669 | rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); |
1671 | rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); | 1670 | rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); |
1672 | 1671 | ||
1673 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); | ||
1674 | if (rf->channel <= 14) { | 1672 | if (rf->channel <= 14) { |
1675 | int idx = rf->channel-1; | 1673 | int idx = rf->channel-1; |
1676 | 1674 | ||
1677 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) { | 1675 | if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { |
1678 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) { | 1676 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) { |
1679 | /* r55/r59 value array of channel 1~14 */ | 1677 | /* r55/r59 value array of channel 1~14 */ |
1680 | static const char r55_bt_rev[] = {0x83, 0x83, | 1678 | static const char r55_bt_rev[] = {0x83, 0x83, |
@@ -2917,8 +2915,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) | |||
2917 | ant = (div_mode == 3) ? 1 : 0; | 2915 | ant = (div_mode == 3) ? 1 : 0; |
2918 | 2916 | ||
2919 | /* check if this is a Bluetooth combo card */ | 2917 | /* check if this is a Bluetooth combo card */ |
2920 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); | 2918 | if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { |
2921 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) { | ||
2922 | u32 reg; | 2919 | u32 reg; |
2923 | 2920 | ||
2924 | rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); | 2921 | rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); |
@@ -3727,16 +3724,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
3727 | } | 3724 | } |
3728 | 3725 | ||
3729 | /* | 3726 | /* |
3730 | * Read frequency offset and RF programming sequence. | 3727 | * Determine external LNA informations. |
3731 | */ | ||
3732 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); | ||
3733 | rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); | ||
3734 | |||
3735 | /* | ||
3736 | * Read external LNA informations. | ||
3737 | */ | 3728 | */ |
3738 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); | ||
3739 | |||
3740 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G)) | 3729 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G)) |
3741 | __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); | 3730 | __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); |
3742 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G)) | 3731 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G)) |
@@ -3749,6 +3738,18 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
3749 | __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); | 3738 | __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); |
3750 | 3739 | ||
3751 | /* | 3740 | /* |
3741 | * Detect if this device has Bluetooth co-existence. | ||
3742 | */ | ||
3743 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) | ||
3744 | __set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags); | ||
3745 | |||
3746 | /* | ||
3747 | * Read frequency offset and RF programming sequence. | ||
3748 | */ | ||
3749 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); | ||
3750 | rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); | ||
3751 | |||
3752 | /* | ||
3752 | * Store led settings, for correct led behaviour. | 3753 | * Store led settings, for correct led behaviour. |
3753 | */ | 3754 | */ |
3754 | #ifdef CONFIG_RT2X00_LIB_LEDS | 3755 | #ifdef CONFIG_RT2X00_LIB_LEDS |
@@ -3756,7 +3757,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
3756 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); | 3757 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); |
3757 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); | 3758 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); |
3758 | 3759 | ||
3759 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); | 3760 | rt2x00dev->led_mcu_reg = eeprom; |
3760 | #endif /* CONFIG_RT2X00_LIB_LEDS */ | 3761 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
3761 | 3762 | ||
3762 | /* | 3763 | /* |
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 08d3947fcb26..cc4a54f571b8 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -302,8 +302,8 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev, | |||
302 | /* | 302 | /* |
303 | * Write firmware to device. | 303 | * Write firmware to device. |
304 | */ | 304 | */ |
305 | rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, | 305 | rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, |
306 | data, len); | 306 | data, len); |
307 | 307 | ||
308 | rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); | 308 | rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); |
309 | rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); | 309 | rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 0d4e8fa3e1f8..0eb44cf2f44a 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -114,12 +114,12 @@ static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev) | |||
114 | return false; | 114 | return false; |
115 | } | 115 | } |
116 | 116 | ||
117 | static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, | 117 | static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, |
118 | int urb_status, u32 tx_status) | 118 | int urb_status, u32 tx_status) |
119 | { | 119 | { |
120 | if (urb_status) { | 120 | if (urb_status) { |
121 | WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status); | 121 | WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status); |
122 | return; | 122 | return false; |
123 | } | 123 | } |
124 | 124 | ||
125 | /* try to read all TX_STA_FIFO entries before scheduling txdone_work */ | 125 | /* 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, | |||
129 | "drop tx status report.\n"); | 129 | "drop tx status report.\n"); |
130 | queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); | 130 | queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); |
131 | } else | 131 | } else |
132 | rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, | 132 | return true; |
133 | rt2800usb_tx_sta_fifo_read_completed); | ||
134 | } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) { | 133 | } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) { |
135 | queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); | 134 | queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); |
136 | } else if (rt2800usb_txstatus_pending(rt2x00dev)) { | 135 | } else if (rt2800usb_txstatus_pending(rt2x00dev)) { |
137 | mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20)); | 136 | mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); |
138 | } | 137 | } |
138 | |||
139 | return false; | ||
139 | } | 140 | } |
140 | 141 | ||
141 | static void rt2800usb_tx_dma_done(struct queue_entry *entry) | 142 | static void rt2800usb_tx_dma_done(struct queue_entry *entry) |
@@ -493,7 +494,7 @@ static void rt2800usb_work_txdone(struct work_struct *work) | |||
493 | * also delayed -> use a timer to retrieve it. | 494 | * also delayed -> use a timer to retrieve it. |
494 | */ | 495 | */ |
495 | if (rt2800usb_txstatus_pending(rt2x00dev)) | 496 | if (rt2800usb_txstatus_pending(rt2x00dev)) |
496 | mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20)); | 497 | mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); |
497 | } | 498 | } |
498 | 499 | ||
499 | /* | 500 | /* |
@@ -633,6 +634,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
633 | __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); | 634 | __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); |
634 | __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); | 635 | __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); |
635 | __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); | 636 | __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); |
637 | __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); | ||
636 | 638 | ||
637 | setup_timer(&rt2x00dev->txstatus_timer, | 639 | setup_timer(&rt2x00dev->txstatus_timer, |
638 | rt2800usb_tx_sta_fifo_timeout, | 640 | rt2800usb_tx_sta_fifo_timeout, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 9d1a158e2c33..c446db69bd3c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -662,6 +662,7 @@ enum rt2x00_state_flags { | |||
662 | * Driver configuration | 662 | * Driver configuration |
663 | */ | 663 | */ |
664 | CONFIG_CHANNEL_HT40, | 664 | CONFIG_CHANNEL_HT40, |
665 | CONFIG_POWERSAVING, | ||
665 | }; | 666 | }; |
666 | 667 | ||
667 | /* | 668 | /* |
@@ -681,6 +682,7 @@ enum rt2x00_capability_flags { | |||
681 | REQUIRE_TASKLET_CONTEXT, | 682 | REQUIRE_TASKLET_CONTEXT, |
682 | REQUIRE_SW_SEQNO, | 683 | REQUIRE_SW_SEQNO, |
683 | REQUIRE_HT_TX_DESC, | 684 | REQUIRE_HT_TX_DESC, |
685 | REQUIRE_PS_AUTOWAKE, | ||
684 | 686 | ||
685 | /* | 687 | /* |
686 | * Capabilities | 688 | * Capabilities |
@@ -697,6 +699,7 @@ enum rt2x00_capability_flags { | |||
697 | CAPABILITY_EXTERNAL_LNA_A, | 699 | CAPABILITY_EXTERNAL_LNA_A, |
698 | CAPABILITY_EXTERNAL_LNA_BG, | 700 | CAPABILITY_EXTERNAL_LNA_BG, |
699 | CAPABILITY_DOUBLE_ANTENNA, | 701 | CAPABILITY_DOUBLE_ANTENNA, |
702 | CAPABILITY_BT_COEXIST, | ||
700 | }; | 703 | }; |
701 | 704 | ||
702 | /* | 705 | /* |
@@ -874,10 +877,20 @@ struct rt2x00_dev { | |||
874 | u8 calibration[2]; | 877 | u8 calibration[2]; |
875 | 878 | ||
876 | /* | 879 | /* |
880 | * Association id. | ||
881 | */ | ||
882 | u16 aid; | ||
883 | |||
884 | /* | ||
877 | * Beacon interval. | 885 | * Beacon interval. |
878 | */ | 886 | */ |
879 | u16 beacon_int; | 887 | u16 beacon_int; |
880 | 888 | ||
889 | /** | ||
890 | * Timestamp of last received beacon | ||
891 | */ | ||
892 | unsigned long last_beacon; | ||
893 | |||
881 | /* | 894 | /* |
882 | * Low level statistics which will have | 895 | * Low level statistics which will have |
883 | * to be kept up to date while device is running. | 896 | * to be kept up to date while device is running. |
@@ -906,6 +919,11 @@ struct rt2x00_dev { | |||
906 | struct work_struct txdone_work; | 919 | struct work_struct txdone_work; |
907 | 920 | ||
908 | /* | 921 | /* |
922 | * Powersaving work | ||
923 | */ | ||
924 | struct delayed_work autowakeup_work; | ||
925 | |||
926 | /* | ||
909 | * Data queue arrays for RX, TX, Beacon and ATIM. | 927 | * Data queue arrays for RX, TX, Beacon and ATIM. |
910 | */ | 928 | */ |
911 | unsigned int data_queues; | 929 | unsigned int data_queues; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index f78726404592..555180d8f4aa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c | |||
@@ -100,6 +100,10 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, | |||
100 | erp.basic_rates = bss_conf->basic_rates; | 100 | erp.basic_rates = bss_conf->basic_rates; |
101 | erp.beacon_int = bss_conf->beacon_int; | 101 | erp.beacon_int = bss_conf->beacon_int; |
102 | 102 | ||
103 | /* Update the AID, this is needed for dynamic PS support */ | ||
104 | rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; | ||
105 | rt2x00dev->last_beacon = bss_conf->timestamp; | ||
106 | |||
103 | /* Update global beacon interval time, this is needed for PS support */ | 107 | /* Update global beacon interval time, this is needed for PS support */ |
104 | rt2x00dev->beacon_int = bss_conf->beacon_int; | 108 | rt2x00dev->beacon_int = bss_conf->beacon_int; |
105 | 109 | ||
@@ -204,6 +208,9 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, | |||
204 | { | 208 | { |
205 | struct rt2x00lib_conf libconf; | 209 | struct rt2x00lib_conf libconf; |
206 | u16 hw_value; | 210 | u16 hw_value; |
211 | u16 autowake_timeout; | ||
212 | u16 beacon_int; | ||
213 | u16 beacon_diff; | ||
207 | 214 | ||
208 | memset(&libconf, 0, sizeof(libconf)); | 215 | memset(&libconf, 0, sizeof(libconf)); |
209 | 216 | ||
@@ -227,6 +234,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, | |||
227 | sizeof(libconf.channel)); | 234 | sizeof(libconf.channel)); |
228 | } | 235 | } |
229 | 236 | ||
237 | if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && | ||
238 | (ieee80211_flags & IEEE80211_CONF_CHANGE_PS)) | ||
239 | cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); | ||
240 | |||
230 | /* | 241 | /* |
231 | * Start configuration. | 242 | * Start configuration. |
232 | */ | 243 | */ |
@@ -239,6 +250,26 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, | |||
239 | if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) | 250 | if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) |
240 | rt2x00link_reset_tuner(rt2x00dev, false); | 251 | rt2x00link_reset_tuner(rt2x00dev, false); |
241 | 252 | ||
253 | if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && | ||
254 | (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) && | ||
255 | (conf->flags & IEEE80211_CONF_PS)) { | ||
256 | beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon; | ||
257 | beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int); | ||
258 | |||
259 | if (beacon_diff > beacon_int) | ||
260 | beacon_diff = 0; | ||
261 | |||
262 | autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff; | ||
263 | queue_delayed_work(rt2x00dev->workqueue, | ||
264 | &rt2x00dev->autowakeup_work, | ||
265 | autowake_timeout - 15); | ||
266 | } | ||
267 | |||
268 | if (conf->flags & IEEE80211_CONF_PS) | ||
269 | set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); | ||
270 | else | ||
271 | clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); | ||
272 | |||
242 | rt2x00dev->curr_band = conf->channel->band; | 273 | rt2x00dev->curr_band = conf->channel->band; |
243 | rt2x00dev->curr_freq = conf->channel->center_freq; | 274 | rt2x00dev->curr_freq = conf->channel->center_freq; |
244 | rt2x00dev->tx_power = conf->power_level; | 275 | rt2x00dev->tx_power = conf->power_level; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 7776d9f1f297..2eb5196977fd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -141,6 +141,16 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) | |||
141 | rt2x00dev); | 141 | rt2x00dev); |
142 | } | 142 | } |
143 | 143 | ||
144 | static void rt2x00lib_autowakeup(struct work_struct *work) | ||
145 | { | ||
146 | struct rt2x00_dev *rt2x00dev = | ||
147 | container_of(work, struct rt2x00_dev, autowakeup_work.work); | ||
148 | |||
149 | if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) | ||
150 | ERROR(rt2x00dev, "Device failed to wakeup.\n"); | ||
151 | clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); | ||
152 | } | ||
153 | |||
144 | /* | 154 | /* |
145 | * Interrupt context handlers. | 155 | * Interrupt context handlers. |
146 | */ | 156 | */ |
@@ -416,6 +426,77 @@ void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status) | |||
416 | } | 426 | } |
417 | EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo); | 427 | EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo); |
418 | 428 | ||
429 | static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie) | ||
430 | { | ||
431 | struct ieee80211_mgmt *mgmt = (void *)data; | ||
432 | u8 *pos, *end; | ||
433 | |||
434 | pos = (u8 *)mgmt->u.beacon.variable; | ||
435 | end = data + len; | ||
436 | while (pos < end) { | ||
437 | if (pos + 2 + pos[1] > end) | ||
438 | return NULL; | ||
439 | |||
440 | if (pos[0] == ie) | ||
441 | return pos; | ||
442 | |||
443 | pos += 2 + pos[1]; | ||
444 | } | ||
445 | |||
446 | return NULL; | ||
447 | } | ||
448 | |||
449 | static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, | ||
450 | struct sk_buff *skb, | ||
451 | struct rxdone_entry_desc *rxdesc) | ||
452 | { | ||
453 | struct ieee80211_hdr *hdr = (void *) skb->data; | ||
454 | struct ieee80211_tim_ie *tim_ie; | ||
455 | u8 *tim; | ||
456 | u8 tim_len; | ||
457 | bool cam; | ||
458 | |||
459 | /* If this is not a beacon, or if mac80211 has no powersaving | ||
460 | * configured, or if the device is already in powersaving mode | ||
461 | * we can exit now. */ | ||
462 | if (likely(!ieee80211_is_beacon(hdr->frame_control) || | ||
463 | !(rt2x00dev->hw->conf.flags & IEEE80211_CONF_PS))) | ||
464 | return; | ||
465 | |||
466 | /* min. beacon length + FCS_LEN */ | ||
467 | if (skb->len <= 40 + FCS_LEN) | ||
468 | return; | ||
469 | |||
470 | /* and only beacons from the associated BSSID, please */ | ||
471 | if (!(rxdesc->dev_flags & RXDONE_MY_BSS) || | ||
472 | !rt2x00dev->aid) | ||
473 | return; | ||
474 | |||
475 | rt2x00dev->last_beacon = jiffies; | ||
476 | |||
477 | tim = rt2x00lib_find_ie(skb->data, skb->len - FCS_LEN, WLAN_EID_TIM); | ||
478 | if (!tim) | ||
479 | return; | ||
480 | |||
481 | if (tim[1] < sizeof(*tim_ie)) | ||
482 | return; | ||
483 | |||
484 | tim_len = tim[1]; | ||
485 | tim_ie = (struct ieee80211_tim_ie *) &tim[2]; | ||
486 | |||
487 | /* Check whenever the PHY can be turned off again. */ | ||
488 | |||
489 | /* 1. What about buffered unicast traffic for our AID? */ | ||
490 | cam = ieee80211_check_tim(tim_ie, tim_len, rt2x00dev->aid); | ||
491 | |||
492 | /* 2. Maybe the AP wants to send multicast/broadcast data? */ | ||
493 | cam |= (tim_ie->bitmap_ctrl & 0x01); | ||
494 | |||
495 | if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) | ||
496 | rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, | ||
497 | IEEE80211_CONF_CHANGE_PS); | ||
498 | } | ||
499 | |||
419 | static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, | 500 | static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, |
420 | struct rxdone_entry_desc *rxdesc) | 501 | struct rxdone_entry_desc *rxdesc) |
421 | { | 502 | { |
@@ -531,6 +612,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry) | |||
531 | rxdesc.flags |= RX_FLAG_HT; | 612 | rxdesc.flags |= RX_FLAG_HT; |
532 | 613 | ||
533 | /* | 614 | /* |
615 | * Check if this is a beacon, and more frames have been | ||
616 | * buffered while we were in powersaving mode. | ||
617 | */ | ||
618 | rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc); | ||
619 | |||
620 | /* | ||
534 | * Update extra components | 621 | * Update extra components |
535 | */ | 622 | */ |
536 | rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); | 623 | rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); |
@@ -1017,6 +1104,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) | |||
1017 | } | 1104 | } |
1018 | 1105 | ||
1019 | INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); | 1106 | INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); |
1107 | INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); | ||
1020 | 1108 | ||
1021 | /* | 1109 | /* |
1022 | * Let the driver probe the device to detect the capabilities. | 1110 | * Let the driver probe the device to detect the capabilities. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index cb208d589ff8..39e1052123e3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c | |||
@@ -170,19 +170,22 @@ struct rt2x00_async_read_data { | |||
170 | __le32 reg; | 170 | __le32 reg; |
171 | struct usb_ctrlrequest cr; | 171 | struct usb_ctrlrequest cr; |
172 | struct rt2x00_dev *rt2x00dev; | 172 | struct rt2x00_dev *rt2x00dev; |
173 | void (*callback)(struct rt2x00_dev *,int,u32); | 173 | bool (*callback)(struct rt2x00_dev *, int, u32); |
174 | }; | 174 | }; |
175 | 175 | ||
176 | static void rt2x00usb_register_read_async_cb(struct urb *urb) | 176 | static void rt2x00usb_register_read_async_cb(struct urb *urb) |
177 | { | 177 | { |
178 | struct rt2x00_async_read_data *rd = urb->context; | 178 | struct rt2x00_async_read_data *rd = urb->context; |
179 | rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg)); | 179 | if (rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg))) { |
180 | kfree(urb->context); | 180 | if (usb_submit_urb(urb, GFP_ATOMIC) < 0) |
181 | kfree(rd); | ||
182 | } else | ||
183 | kfree(rd); | ||
181 | } | 184 | } |
182 | 185 | ||
183 | void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, | 186 | void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, |
184 | const unsigned int offset, | 187 | const unsigned int offset, |
185 | void (*callback)(struct rt2x00_dev*,int,u32)) | 188 | bool (*callback)(struct rt2x00_dev*, int, u32)) |
186 | { | 189 | { |
187 | struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); | 190 | struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); |
188 | struct urb *urb; | 191 | struct urb *urb; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 64be34f612f6..323ca7b2b095 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h | |||
@@ -349,10 +349,12 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, | |||
349 | * be called from atomic context. The callback will be called | 349 | * be called from atomic context. The callback will be called |
350 | * when the URB completes. Otherwise the function is similar | 350 | * when the URB completes. Otherwise the function is similar |
351 | * to rt2x00usb_register_read(). | 351 | * to rt2x00usb_register_read(). |
352 | * When the callback function returns false, the memory will be cleaned up, | ||
353 | * when it returns true, the urb will be fired again. | ||
352 | */ | 354 | */ |
353 | void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, | 355 | void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, |
354 | const unsigned int offset, | 356 | const unsigned int offset, |
355 | void (*callback)(struct rt2x00_dev*,int,u32)); | 357 | bool (*callback)(struct rt2x00_dev*, int, u32)); |
356 | 358 | ||
357 | /* | 359 | /* |
358 | * Radio handlers | 360 | * Radio handlers |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index a6ce7d6cbdfa..ad20953cbf05 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -2209,6 +2209,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
2209 | if (!modparam_nohwcrypt) | 2209 | if (!modparam_nohwcrypt) |
2210 | __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); | 2210 | __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); |
2211 | __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); | 2211 | __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); |
2212 | __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); | ||
2212 | 2213 | ||
2213 | /* | 2214 | /* |
2214 | * Set the rssi offset. | 2215 | * Set the rssi offset. |