aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h17
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c31
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c88
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c1
6 files changed, 139 insertions, 0 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/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index b5d5f2203c52..0eb44cf2f44a 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -634,6 +634,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
634 __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); 634 __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
635 __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); 635 __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags);
636 __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);
637 638
638 setup_timer(&rt2x00dev->txstatus_timer, 639 setup_timer(&rt2x00dev->txstatus_timer,
639 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 86e141000156..73d3332be614 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
@@ -875,10 +877,20 @@ struct rt2x00_dev {
875 u8 calibration[2]; 877 u8 calibration[2];
876 878
877 /* 879 /*
880 * Association id.
881 */
882 u16 aid;
883
884 /*
878 * Beacon interval. 885 * Beacon interval.
879 */ 886 */
880 u16 beacon_int; 887 u16 beacon_int;
881 888
889 /**
890 * Timestamp of last received beacon
891 */
892 unsigned long last_beacon;
893
882 /* 894 /*
883 * Low level statistics which will have 895 * Low level statistics which will have
884 * to be kept up to date while device is running. 896 * to be kept up to date while device is running.
@@ -907,6 +919,11 @@ struct rt2x00_dev {
907 struct work_struct txdone_work; 919 struct work_struct txdone_work;
908 920
909 /* 921 /*
922 * Powersaving work
923 */
924 struct delayed_work autowakeup_work;
925
926 /*
910 * Data queue arrays for RX, TX, Beacon and ATIM. 927 * Data queue arrays for RX, TX, Beacon and ATIM.
911 */ 928 */
912 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 2a313b6d378d..edebbf04bc57 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
144static 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}
417EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo); 427EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo);
418 428
429static 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
449static 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
419static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, 500static 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/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.