aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2008-11-29 16:33:57 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-12-05 09:35:43 -0500
commitc772a08ba7192fa5450f85ef53adcbc6e0c5e1c9 (patch)
treece348a77eccbad1b21f7e938b8f6944f5c01362c
parent4571d3bf87b76eae875283ff9f7243984b5ddcae (diff)
p54: revamp station power save management in access point mode
This patch addresses the problem in: http://marc.info/?l=linux-wireless&m=122727674810057&w=2 Thanks to Stefan Steuerwald <salsasepp@googlemail.com> extensive iPod touch tests. We could finally squash some bugs in p54's master mode / access point implementation. Let's hope we got everything right this time and all stations from now on will wake up on TIM and receive their queued frames and go to sleep again without any hiccups. Signed-off-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/p54/p54common.c73
-rw-r--r--drivers/net/wireless/p54/p54common.h2
2 files changed, 49 insertions, 26 deletions
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 602392628e4e..de92b58d4508 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -652,6 +652,10 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
652 __skb_unlink(entry, &priv->tx_queue); 652 __skb_unlink(entry, &priv->tx_queue);
653 spin_unlock_irqrestore(&priv->tx_queue.lock, flags); 653 spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
654 654
655 entry_hdr = (struct p54_hdr *) entry->data;
656 entry_data = (struct p54_tx_data *) entry_hdr->data;
657 priv->tx_stats[entry_data->hw_queue].len--;
658
655 if (unlikely(entry == priv->cached_beacon)) { 659 if (unlikely(entry == priv->cached_beacon)) {
656 kfree_skb(entry); 660 kfree_skb(entry);
657 priv->cached_beacon = NULL; 661 priv->cached_beacon = NULL;
@@ -668,8 +672,6 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
668 BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, 672 BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
669 status.ampdu_ack_len) != 23); 673 status.ampdu_ack_len) != 23);
670 674
671 entry_hdr = (struct p54_hdr *) entry->data;
672 entry_data = (struct p54_tx_data *) entry_hdr->data;
673 if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) 675 if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
674 pad = entry_data->align[0]; 676 pad = entry_data->align[0];
675 677
@@ -687,7 +689,6 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
687 } 689 }
688 } 690 }
689 691
690 priv->tx_stats[entry_data->hw_queue].len--;
691 if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && 692 if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
692 (!payload->status)) 693 (!payload->status))
693 info->flags |= IEEE80211_TX_STAT_ACK; 694 info->flags |= IEEE80211_TX_STAT_ACK;
@@ -1004,6 +1005,38 @@ static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
1004 return 0; 1005 return 0;
1005} 1006}
1006 1007
1008static void p54_sta_notify_ps(struct ieee80211_hw *dev,
1009 enum sta_notify_ps_cmd notify_cmd,
1010 struct ieee80211_sta *sta)
1011{
1012 switch (notify_cmd) {
1013 case STA_NOTIFY_AWAKE:
1014 p54_sta_unlock(dev, sta->addr);
1015 break;
1016 default:
1017 break;
1018 }
1019}
1020
1021static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
1022 enum sta_notify_cmd notify_cmd,
1023 struct ieee80211_sta *sta)
1024{
1025 switch (notify_cmd) {
1026 case STA_NOTIFY_ADD:
1027 case STA_NOTIFY_REMOVE:
1028 /*
1029 * Notify the firmware that we don't want or we don't
1030 * need to buffer frames for this station anymore.
1031 */
1032
1033 p54_sta_unlock(dev, sta->addr);
1034 break;
1035 default:
1036 break;
1037 }
1038}
1039
1007static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry) 1040static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
1008{ 1041{
1009 struct p54_common *priv = dev->priv; 1042 struct p54_common *priv = dev->priv;
@@ -1069,7 +1102,7 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
1069 if (info->control.sta) 1102 if (info->control.sta)
1070 *aid = info->control.sta->aid; 1103 *aid = info->control.sta->aid;
1071 else 1104 else
1072 *flags = P54_HDR_FLAG_DATA_OUT_NOCANCEL; 1105 *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
1073 } 1106 }
1074 return ret; 1107 return ret;
1075} 1108}
@@ -1082,7 +1115,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
1082 struct p54_hdr *hdr; 1115 struct p54_hdr *hdr;
1083 struct p54_tx_data *txhdr; 1116 struct p54_tx_data *txhdr;
1084 size_t padding, len, tim_len = 0; 1117 size_t padding, len, tim_len = 0;
1085 int i, j, ridx; 1118 int i, j, ridx, ret;
1086 u16 hdr_flags = 0, aid = 0; 1119 u16 hdr_flags = 0, aid = 0;
1087 u8 rate, queue; 1120 u8 rate, queue;
1088 u8 cts_rate = 0x20; 1121 u8 cts_rate = 0x20;
@@ -1092,30 +1125,18 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
1092 1125
1093 queue = skb_get_queue_mapping(skb); 1126 queue = skb_get_queue_mapping(skb);
1094 1127
1095 if (p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid)) { 1128 ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid);
1096 current_queue = &priv->tx_stats[queue]; 1129 current_queue = &priv->tx_stats[queue];
1097 if (unlikely(current_queue->len > current_queue->limit)) 1130 if (unlikely((current_queue->len > current_queue->limit) && ret))
1098 return NETDEV_TX_BUSY; 1131 return NETDEV_TX_BUSY;
1099 current_queue->len++; 1132 current_queue->len++;
1100 current_queue->count++; 1133 current_queue->count++;
1101 if (current_queue->len == current_queue->limit) 1134 if ((current_queue->len == current_queue->limit) && ret)
1102 ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); 1135 ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
1103 }
1104 1136
1105 padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; 1137 padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
1106 len = skb->len; 1138 len = skb->len;
1107 1139
1108 if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) {
1109 if (info->control.sta)
1110 if (p54_sta_unlock(dev, info->control.sta->addr)) {
1111 if (current_queue) {
1112 current_queue->len--;
1113 current_queue->count--;
1114 }
1115 return NETDEV_TX_BUSY;
1116 }
1117 }
1118
1119 txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); 1140 txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
1120 hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); 1141 hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
1121 1142
@@ -1834,6 +1855,8 @@ static const struct ieee80211_ops p54_ops = {
1834 .add_interface = p54_add_interface, 1855 .add_interface = p54_add_interface,
1835 .remove_interface = p54_remove_interface, 1856 .remove_interface = p54_remove_interface,
1836 .set_tim = p54_set_tim, 1857 .set_tim = p54_set_tim,
1858 .sta_notify_ps = p54_sta_notify_ps,
1859 .sta_notify = p54_sta_notify,
1837 .config = p54_config, 1860 .config = p54_config,
1838 .config_interface = p54_config_interface, 1861 .config_interface = p54_config_interface,
1839 .bss_info_changed = p54_bss_info_changed, 1862 .bss_info_changed = p54_bss_info_changed,
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
index 3419f16be938..d292ffbec08c 100644
--- a/drivers/net/wireless/p54/p54common.h
+++ b/drivers/net/wireless/p54/p54common.h
@@ -302,7 +302,7 @@ enum p54_frame_sent_status {
302 P54_TX_OK = 0, 302 P54_TX_OK = 0,
303 P54_TX_FAILED, 303 P54_TX_FAILED,
304 P54_TX_PSM, 304 P54_TX_PSM,
305 P54_TX_PSM_CANCELLED 305 P54_TX_PSM_CANCELLED = 4
306}; 306};
307 307
308struct p54_frame_sent { 308struct p54_frame_sent {