diff options
-rw-r--r-- | include/net/mac80211.h | 6 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 10 | ||||
-rw-r--r-- | net/mac80211/main.c | 7 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 49 | ||||
-rw-r--r-- | net/mac80211/tx.c | 13 | ||||
-rw-r--r-- | net/mac80211/wext.c | 30 |
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 | */ |
858 | enum ieee80211_hw_flags { | 863 | enum 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 | ||
541 | enum queue_stop_reason { | 541 | enum 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); | |||
977 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, | 983 | u64 ieee80211_mandatory_rates(struct ieee80211_local *local, |
978 | enum ieee80211_band band); | 984 | enum ieee80211_band band); |
979 | 985 | ||
986 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); | ||
987 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); | ||
988 | void ieee80211_dynamic_ps_timer(unsigned long data); | ||
989 | |||
980 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 990 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
981 | enum queue_stop_reason reason); | 991 | enum queue_stop_reason reason); |
982 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 992 | void 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 | |||
2606 | void 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 | |||
2621 | void 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 | |||
2635 | void 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 | ||
860 | set: | 861 | set: |
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 | ||