diff options
author | Arik Nemtsov <arik@wizery.com> | 2011-01-31 15:29:13 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-02-03 16:44:44 -0500 |
commit | d057e5a381cbaec5632117bf62ba49438ab16214 (patch) | |
tree | 723bd8c982747393b3f390b2c0ea75eb0c6bb62e /net | |
parent | 8fd369eeaa81d05969787c9ddf9cf3f1a8c4e084 (diff) |
mac80211: add HW flag for disabling auto link-PS in AP mode
When operating in AP mode the wl1271 hardware filters out null-data
packets as well as management packets. This makes it impossible for
mac80211 to monitor the PS mode by using the PM bit of incoming frames.
Implement a HW flag to indicate that mac80211 should ignore the PM bit.
In addition, expose ieee80211_sta_ps_transition() to make low-level
drivers capable of controlling PS-mode.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/rx.c | 27 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 3 | ||||
-rw-r--r-- | net/mac80211/status.c | 4 |
3 files changed, 31 insertions, 3 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7185c9316be2..d78d6fc333d2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1105,7 +1105,8 @@ static void ap_sta_ps_start(struct sta_info *sta) | |||
1105 | 1105 | ||
1106 | atomic_inc(&sdata->bss->num_sta_ps); | 1106 | atomic_inc(&sdata->bss->num_sta_ps); |
1107 | set_sta_flags(sta, WLAN_STA_PS_STA); | 1107 | set_sta_flags(sta, WLAN_STA_PS_STA); |
1108 | drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); | 1108 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
1109 | drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); | ||
1109 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1110 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
1110 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", | 1111 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", |
1111 | sdata->name, sta->sta.addr, sta->sta.aid); | 1112 | sdata->name, sta->sta.addr, sta->sta.aid); |
@@ -1134,6 +1135,27 @@ static void ap_sta_ps_end(struct sta_info *sta) | |||
1134 | ieee80211_sta_ps_deliver_wakeup(sta); | 1135 | ieee80211_sta_ps_deliver_wakeup(sta); |
1135 | } | 1136 | } |
1136 | 1137 | ||
1138 | int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start) | ||
1139 | { | ||
1140 | struct sta_info *sta_inf = container_of(sta, struct sta_info, sta); | ||
1141 | bool in_ps; | ||
1142 | |||
1143 | WARN_ON(!(sta_inf->local->hw.flags & IEEE80211_HW_AP_LINK_PS)); | ||
1144 | |||
1145 | /* Don't let the same PS state be set twice */ | ||
1146 | in_ps = test_sta_flags(sta_inf, WLAN_STA_PS_STA); | ||
1147 | if ((start && in_ps) || (!start && !in_ps)) | ||
1148 | return -EINVAL; | ||
1149 | |||
1150 | if (start) | ||
1151 | ap_sta_ps_start(sta_inf); | ||
1152 | else | ||
1153 | ap_sta_ps_end(sta_inf); | ||
1154 | |||
1155 | return 0; | ||
1156 | } | ||
1157 | EXPORT_SYMBOL(ieee80211_sta_ps_transition); | ||
1158 | |||
1137 | static ieee80211_rx_result debug_noinline | 1159 | static ieee80211_rx_result debug_noinline |
1138 | ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | 1160 | ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) |
1139 | { | 1161 | { |
@@ -1178,7 +1200,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1178 | * Change STA power saving mode only at the end of a frame | 1200 | * Change STA power saving mode only at the end of a frame |
1179 | * exchange sequence. | 1201 | * exchange sequence. |
1180 | */ | 1202 | */ |
1181 | if (!ieee80211_has_morefrags(hdr->frame_control) && | 1203 | if (!(sta->local->hw.flags & IEEE80211_HW_AP_LINK_PS) && |
1204 | !ieee80211_has_morefrags(hdr->frame_control) && | ||
1182 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && | 1205 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && |
1183 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || | 1206 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || |
1184 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { | 1207 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c426504ed1cf..5a11078827ab 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -899,7 +899,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
899 | struct ieee80211_local *local = sdata->local; | 899 | struct ieee80211_local *local = sdata->local; |
900 | int sent, buffered; | 900 | int sent, buffered; |
901 | 901 | ||
902 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); | 902 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
903 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); | ||
903 | 904 | ||
904 | if (!skb_queue_empty(&sta->ps_tx_buf)) | 905 | if (!skb_queue_empty(&sta->ps_tx_buf)) |
905 | sta_info_clear_tim_bit(sta); | 906 | sta_info_clear_tim_bit(sta); |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 38a797217a91..ffb0de9bc2fa 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -98,6 +98,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
98 | * (b) always process RX events before TX status events if ordering | 98 | * (b) always process RX events before TX status events if ordering |
99 | * can be unknown, for example with different interrupt status | 99 | * can be unknown, for example with different interrupt status |
100 | * bits. | 100 | * bits. |
101 | * (c) if PS mode transitions are manual (i.e. the flag | ||
102 | * %IEEE80211_HW_AP_LINK_PS is set), always process PS state | ||
103 | * changes before calling TX status events if ordering can be | ||
104 | * unknown. | ||
101 | */ | 105 | */ |
102 | if (test_sta_flags(sta, WLAN_STA_PS_STA) && | 106 | if (test_sta_flags(sta, WLAN_STA_PS_STA) && |
103 | skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { | 107 | skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { |