aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-11-06 05:35:50 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-06 16:49:10 -0500
commitaf81858172cc0f3da81946aab919c26e4b364efc (patch)
tree8e7a4bf30ff7c23636d810c5a912ff7e3ddb7333 /net/mac80211/rx.c
parent70d9f405d09e334b609702d88ee03b6119c4b45e (diff)
mac80211: async station powersave handling
Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r--net/mac80211/rx.c86
1 files changed, 15 insertions, 71 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index c06496f0b76d..28316b2a585f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -781,7 +781,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
781 struct ieee80211_local *local = sdata->local; 781 struct ieee80211_local *local = sdata->local;
782 782
783 atomic_inc(&sdata->bss->num_sta_ps); 783 atomic_inc(&sdata->bss->num_sta_ps);
784 set_sta_flags(sta, WLAN_STA_PS); 784 set_sta_flags(sta, WLAN_STA_PS_STA);
785 drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); 785 drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta);
786#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 786#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
787 printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", 787 printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
@@ -792,33 +792,25 @@ static void ap_sta_ps_start(struct sta_info *sta)
792static void ap_sta_ps_end(struct sta_info *sta) 792static void ap_sta_ps_end(struct sta_info *sta)
793{ 793{
794 struct ieee80211_sub_if_data *sdata = sta->sdata; 794 struct ieee80211_sub_if_data *sdata = sta->sdata;
795 struct ieee80211_local *local = sdata->local;
796 int sent, buffered;
797 795
798 atomic_dec(&sdata->bss->num_sta_ps); 796 atomic_dec(&sdata->bss->num_sta_ps);
799 797
800 clear_sta_flags(sta, WLAN_STA_PS); 798 clear_sta_flags(sta, WLAN_STA_PS_STA);
801 drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta);
802
803 if (!skb_queue_empty(&sta->ps_tx_buf))
804 sta_info_clear_tim_bit(sta);
805 799
806#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 800#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
807 printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", 801 printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
808 sdata->dev->name, sta->sta.addr, sta->sta.aid); 802 sdata->dev->name, sta->sta.addr, sta->sta.aid);
809#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ 803#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
810 804
811 /* Send all buffered frames to the station */ 805 if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) {
812 sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
813 buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf);
814 sent += buffered;
815 local->total_ps_buffered -= buffered;
816
817#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 806#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
818 printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " 807 printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
819 "since STA not sleeping anymore\n", sdata->dev->name, 808 sdata->dev->name, sta->sta.addr, sta->sta.aid);
820 sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
821#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ 809#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
810 return;
811 }
812
813 ieee80211_sta_ps_deliver_wakeup(sta);
822} 814}
823 815
824static ieee80211_rx_result debug_noinline 816static ieee80211_rx_result debug_noinline
@@ -866,7 +858,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
866 if (!ieee80211_has_morefrags(hdr->frame_control) && 858 if (!ieee80211_has_morefrags(hdr->frame_control) &&
867 (rx->sdata->vif.type == NL80211_IFTYPE_AP || 859 (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
868 rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { 860 rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
869 if (test_sta_flags(sta, WLAN_STA_PS)) { 861 if (test_sta_flags(sta, WLAN_STA_PS_STA)) {
870 /* 862 /*
871 * Ignore doze->wake transitions that are 863 * Ignore doze->wake transitions that are
872 * indicated by non-data frames, the standard 864 * indicated by non-data frames, the standard
@@ -1094,9 +1086,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
1094static ieee80211_rx_result debug_noinline 1086static ieee80211_rx_result debug_noinline
1095ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) 1087ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
1096{ 1088{
1097 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); 1089 struct ieee80211_sub_if_data *sdata = rx->sdata;
1098 struct sk_buff *skb;
1099 int no_pending_pkts;
1100 __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control; 1090 __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control;
1101 1091
1102 if (likely(!rx->sta || !ieee80211_is_pspoll(fc) || 1092 if (likely(!rx->sta || !ieee80211_is_pspoll(fc) ||
@@ -1107,56 +1097,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
1107 (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)) 1097 (sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
1108 return RX_DROP_UNUSABLE; 1098 return RX_DROP_UNUSABLE;
1109 1099
1110 skb = skb_dequeue(&rx->sta->tx_filtered); 1100 if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER))
1111 if (!skb) { 1101 ieee80211_sta_ps_deliver_poll_response(rx->sta);
1112 skb = skb_dequeue(&rx->sta->ps_tx_buf); 1102 else
1113 if (skb) 1103 set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
1114 rx->local->total_ps_buffered--;
1115 }
1116 no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) &&
1117 skb_queue_empty(&rx->sta->ps_tx_buf);
1118
1119 if (skb) {
1120 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1121 struct ieee80211_hdr *hdr =
1122 (struct ieee80211_hdr *) skb->data;
1123
1124 /*
1125 * Tell TX path to send this frame even though the STA may
1126 * still remain is PS mode after this frame exchange.
1127 */
1128 info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE;
1129
1130#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
1131 printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n",
1132 rx->sta->sta.addr, rx->sta->sta.aid,
1133 skb_queue_len(&rx->sta->ps_tx_buf));
1134#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
1135
1136 /* Use MoreData flag to indicate whether there are more
1137 * buffered frames for this STA */
1138 if (no_pending_pkts)
1139 hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
1140 else
1141 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
1142
1143 ieee80211_add_pending_skb(rx->local, skb);
1144
1145 if (no_pending_pkts)
1146 sta_info_clear_tim_bit(rx->sta);
1147#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
1148 } else {
1149 /*
1150 * FIXME: This can be the result of a race condition between
1151 * us expiring a frame and the station polling for it.
1152 * Should we send it a null-func frame indicating we
1153 * have nothing buffered for it?
1154 */
1155 printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
1156 "though there are no buffered frames for it\n",
1157 rx->dev->name, rx->sta->sta.addr);
1158#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
1159 }
1160 1104
1161 /* Free PS Poll skb here instead of returning RX_DROP that would 1105 /* Free PS Poll skb here instead of returning RX_DROP that would
1162 * count as an dropped frame. */ 1106 * count as an dropped frame. */