aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/p54/txrx.c
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2009-07-07 13:08:07 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-24 15:05:06 -0400
commite0f114e82e3781087a0ad0e92c94ff0d55012c1a (patch)
treed4c7cfa485360952b3da9fee7acc07efcfdcc7d8 /drivers/net/wireless/p54/txrx.c
parent0a2b8bb24d4eb67788edd71d1ef8aa86c2e17e0f (diff)
p54: re-enable power save feature
This patch re-enables p54's power save features and adds a workaround which temporarily alters the device's power state in order to allow ps-polls to be sent and buffered data to be retrieved during psm. (Incorporates patch originally posted as "p54: fix beacon template dtim IE corruption". -- JWL) Signed-off-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54/txrx.c')
-rw-r--r--drivers/net/wireless/p54/txrx.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 6426d2cae6d..01eadb1683f 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -288,6 +288,45 @@ static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
288 priv->rssical_db[band].add) / 4; 288 priv->rssical_db[band].add) / 4;
289} 289}
290 290
291/*
292 * Even if the firmware is capable of dealing with incoming traffic,
293 * while dozing, we have to prepared in case mac80211 uses PS-POLL
294 * to retrieve outstanding frames from our AP.
295 * (see comment in net/mac80211/mlme.c @ line 1993)
296 */
297static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
298{
299 struct ieee80211_hdr *hdr = (void *) skb->data;
300 struct ieee80211_tim_ie *tim_ie;
301 u8 *tim;
302 u8 tim_len;
303 bool new_psm;
304
305 /* only beacons have a TIM IE */
306 if (!ieee80211_is_beacon(hdr->frame_control))
307 return;
308
309 if (!priv->aid)
310 return;
311
312 /* only consider beacons from the associated BSSID */
313 if (compare_ether_addr(hdr->addr3, priv->bssid))
314 return;
315
316 tim = p54_find_ie(skb, WLAN_EID_TIM);
317 if (!tim)
318 return;
319
320 tim_len = tim[1];
321 tim_ie = (struct ieee80211_tim_ie *) &tim[2];
322
323 new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid);
324 if (new_psm != priv->powersave_override) {
325 priv->powersave_override = new_psm;
326 p54_set_ps(priv);
327 }
328}
329
291static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb) 330static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
292{ 331{
293 struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; 332 struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
@@ -340,6 +379,9 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
340 379
341 skb_pull(skb, header_len); 380 skb_pull(skb, header_len);
342 skb_trim(skb, le16_to_cpu(hdr->len)); 381 skb_trim(skb, le16_to_cpu(hdr->len));
382 if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
383 p54_pspoll_workaround(priv, skb);
384
343 ieee80211_rx_irqsafe(priv->hw, skb); 385 ieee80211_rx_irqsafe(priv->hw, skb);
344 386
345 queue_delayed_work(priv->hw->workqueue, &priv->work, 387 queue_delayed_work(priv->hw->workqueue, &priv->work,