aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h6
-rw-r--r--net/mac80211/ieee80211_i.h10
-rw-r--r--net/mac80211/main.c7
-rw-r--r--net/mac80211/mlme.c49
-rw-r--r--net/mac80211/tx.c13
-rw-r--r--net/mac80211/wext.c30
6 files changed, 103 insertions, 12 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9428d3e2f113..b3bd00a9d992 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -854,6 +854,11 @@ enum ieee80211_tkip_key_type {
854 * 854 *
855 * @IEEE80211_HW_AMPDU_AGGREGATION: 855 * @IEEE80211_HW_AMPDU_AGGREGATION:
856 * Hardware supports 11n A-MPDU aggregation. 856 * Hardware supports 11n A-MPDU aggregation.
857 *
858 * @IEEE80211_HW_NO_STACK_DYNAMIC_PS:
859 * Hardware which has dynamic power save support, meaning
860 * that power save is enabled in idle periods, and don't need support
861 * from stack.
857 */ 862 */
858enum ieee80211_hw_flags { 863enum ieee80211_hw_flags {
859 IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, 864 IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
@@ -866,6 +871,7 @@ enum ieee80211_hw_flags {
866 IEEE80211_HW_NOISE_DBM = 1<<8, 871 IEEE80211_HW_NOISE_DBM = 1<<8,
867 IEEE80211_HW_SPECTRUM_MGMT = 1<<9, 872 IEEE80211_HW_SPECTRUM_MGMT = 1<<9,
868 IEEE80211_HW_AMPDU_AGGREGATION = 1<<10, 873 IEEE80211_HW_AMPDU_AGGREGATION = 1<<10,
874 IEEE80211_HW_NO_STACK_DYNAMIC_PS = 1<<11,
869}; 875};
870 876
871/** 877/**
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a74d6738b30a..f3eec989662b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -540,6 +540,7 @@ enum {
540 540
541enum queue_stop_reason { 541enum queue_stop_reason {
542 IEEE80211_QUEUE_STOP_REASON_DRIVER, 542 IEEE80211_QUEUE_STOP_REASON_DRIVER,
543 IEEE80211_QUEUE_STOP_REASON_PS,
543}; 544};
544 545
545/* maximum number of hardware queues we support. */ 546/* maximum number of hardware queues we support. */
@@ -693,7 +694,12 @@ struct ieee80211_local {
693 */ 694 */
694 int wifi_wme_noack_test; 695 int wifi_wme_noack_test;
695 unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ 696 unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
697
696 bool powersave; 698 bool powersave;
699 int dynamic_ps_timeout;
700 struct work_struct dynamic_ps_enable_work;
701 struct work_struct dynamic_ps_disable_work;
702 struct timer_list dynamic_ps_timer;
697 703
698#ifdef CONFIG_MAC80211_DEBUGFS 704#ifdef CONFIG_MAC80211_DEBUGFS
699 struct local_debugfsdentries { 705 struct local_debugfsdentries {
@@ -977,6 +983,10 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
977u64 ieee80211_mandatory_rates(struct ieee80211_local *local, 983u64 ieee80211_mandatory_rates(struct ieee80211_local *local,
978 enum ieee80211_band band); 984 enum ieee80211_band band);
979 985
986void ieee80211_dynamic_ps_enable_work(struct work_struct *work);
987void ieee80211_dynamic_ps_disable_work(struct work_struct *work);
988void ieee80211_dynamic_ps_timer(unsigned long data);
989
980void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, 990void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
981 enum queue_stop_reason reason); 991 enum queue_stop_reason reason);
982void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, 992void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 21335382f530..24b14363d6e7 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -729,6 +729,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
729 729
730 INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); 730 INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
731 731
732 INIT_WORK(&local->dynamic_ps_enable_work,
733 ieee80211_dynamic_ps_enable_work);
734 INIT_WORK(&local->dynamic_ps_disable_work,
735 ieee80211_dynamic_ps_disable_work);
736 setup_timer(&local->dynamic_ps_timer,
737 ieee80211_dynamic_ps_timer, (unsigned long) local);
738
732 sta_info_init(local); 739 sta_info_init(local);
733 740
734 tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, 741 tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index dac8bd37dcf5..5ba721b6a399 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -745,8 +745,14 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
745 ieee80211_bss_info_change_notify(sdata, bss_info_changed); 745 ieee80211_bss_info_change_notify(sdata, bss_info_changed);
746 746
747 if (local->powersave) { 747 if (local->powersave) {
748 local->hw.conf.flags |= IEEE80211_CONF_PS; 748 if (local->dynamic_ps_timeout > 0)
749 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 749 mod_timer(&local->dynamic_ps_timer, jiffies +
750 msecs_to_jiffies(local->dynamic_ps_timeout));
751 else {
752 conf->flags |= IEEE80211_CONF_PS;
753 ieee80211_hw_config(local,
754 IEEE80211_CONF_CHANGE_PS);
755 }
750 } 756 }
751 757
752 netif_tx_start_all_queues(sdata->dev); 758 netif_tx_start_all_queues(sdata->dev);
@@ -866,6 +872,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
866 local->oper_channel_type = NL80211_CHAN_NO_HT; 872 local->oper_channel_type = NL80211_CHAN_NO_HT;
867 config_changed |= IEEE80211_CONF_CHANGE_HT; 873 config_changed |= IEEE80211_CONF_CHANGE_HT;
868 874
875 del_timer_sync(&local->dynamic_ps_timer);
876 cancel_work_sync(&local->dynamic_ps_enable_work);
877
869 if (local->hw.conf.flags & IEEE80211_CONF_PS) { 878 if (local->hw.conf.flags & IEEE80211_CONF_PS) {
870 local->hw.conf.flags &= ~IEEE80211_CONF_PS; 879 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
871 config_changed |= IEEE80211_CONF_CHANGE_PS; 880 config_changed |= IEEE80211_CONF_CHANGE_PS;
@@ -2593,3 +2602,39 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
2593 ieee80211_restart_sta_timer(sdata); 2602 ieee80211_restart_sta_timer(sdata);
2594 rcu_read_unlock(); 2603 rcu_read_unlock();
2595} 2604}
2605
2606void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
2607{
2608 struct ieee80211_local *local =
2609 container_of(work, struct ieee80211_local,
2610 dynamic_ps_disable_work);
2611
2612 if (local->hw.conf.flags & IEEE80211_CONF_PS) {
2613 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
2614 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
2615 }
2616
2617 ieee80211_wake_queues_by_reason(&local->hw,
2618 IEEE80211_QUEUE_STOP_REASON_PS);
2619}
2620
2621void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
2622{
2623 struct ieee80211_local *local =
2624 container_of(work, struct ieee80211_local,
2625 dynamic_ps_enable_work);
2626
2627 if (local->hw.conf.flags & IEEE80211_CONF_PS)
2628 return;
2629
2630 local->hw.conf.flags |= IEEE80211_CONF_PS;
2631
2632 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
2633}
2634
2635void ieee80211_dynamic_ps_timer(unsigned long data)
2636{
2637 struct ieee80211_local *local = (void *) data;
2638
2639 queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
2640}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index b098c58d216f..a4af3a124cce 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1473,6 +1473,19 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
1473 goto fail; 1473 goto fail;
1474 } 1474 }
1475 1475
1476 if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
1477 local->dynamic_ps_timeout > 0) {
1478 if (local->hw.conf.flags & IEEE80211_CONF_PS) {
1479 ieee80211_stop_queues_by_reason(&local->hw,
1480 IEEE80211_QUEUE_STOP_REASON_PS);
1481 queue_work(local->hw.workqueue,
1482 &local->dynamic_ps_disable_work);
1483 }
1484
1485 mod_timer(&local->dynamic_ps_timer, jiffies +
1486 msecs_to_jiffies(local->dynamic_ps_timeout));
1487 }
1488
1476 nh_pos = skb_network_header(skb) - skb->data; 1489 nh_pos = skb_network_header(skb) - skb->data;
1477 h_pos = skb_transport_header(skb) - skb->data; 1490 h_pos = skb_transport_header(skb) - skb->data;
1478 1491
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index f6640d047157..7162d5816f39 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -833,7 +833,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
833 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 833 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
834 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 834 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
835 struct ieee80211_conf *conf = &local->hw.conf; 835 struct ieee80211_conf *conf = &local->hw.conf;
836 int ret = 0; 836 int ret = 0, timeout = 0;
837 bool ps; 837 bool ps;
838 838
839 if (sdata->vif.type != NL80211_IFTYPE_STATION) 839 if (sdata->vif.type != NL80211_IFTYPE_STATION)
@@ -841,6 +841,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
841 841
842 if (wrq->disabled) { 842 if (wrq->disabled) {
843 ps = false; 843 ps = false;
844 timeout = 0;
844 goto set; 845 goto set;
845 } 846 }
846 847
@@ -850,22 +851,31 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
850 case IW_POWER_ALL_R: /* If explicitely state all */ 851 case IW_POWER_ALL_R: /* If explicitely state all */
851 ps = true; 852 ps = true;
852 break; 853 break;
853 default: /* Otherwise we don't support it */ 854 default: /* Otherwise we ignore */
854 return -EINVAL; 855 break;
855 } 856 }
856 857
857 if (ps == local->powersave) 858 if (wrq->flags & IW_POWER_TIMEOUT)
858 return ret; 859 timeout = wrq->value / 1000;
859 860
860set: 861set:
862 if (ps == local->powersave && timeout == local->dynamic_ps_timeout)
863 return ret;
864
861 local->powersave = ps; 865 local->powersave = ps;
866 local->dynamic_ps_timeout = timeout;
862 867
863 if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { 868 if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
864 if (local->powersave) 869 if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
865 conf->flags |= IEEE80211_CONF_PS; 870 local->dynamic_ps_timeout > 0)
866 else 871 mod_timer(&local->dynamic_ps_timer, jiffies +
867 conf->flags &= ~IEEE80211_CONF_PS; 872 msecs_to_jiffies(local->dynamic_ps_timeout));
868 873 else {
874 if (local->powersave)
875 conf->flags |= IEEE80211_CONF_PS;
876 else
877 conf->flags &= ~IEEE80211_CONF_PS;
878 }
869 ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 879 ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
870 } 880 }
871 881