aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/wl1271_event.c
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-07-08 10:50:00 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-07-08 16:35:51 -0400
commit90494a90bea010af47547880634e0f1c52824a7d (patch)
treee7464aa406385a0a9908324e038736aa9cac6a4d /drivers/net/wireless/wl12xx/wl1271_event.c
parent849923f43ca681cc86a401178db31acb60e79f3b (diff)
wl1271: Work around AP's with broken ps-poll functionality
Some AP's (such as Zyxel Prestige 600) have totally broken ps-poll functionality. When powersave is enabled, these AP's will set the TIM bit for a STA in beacons, but when the STA responds with a ps-poll, the AP does not respond with data. The wl1271 firmware is able to send an indication to the host, when this problem occurs. This patch adds implementation, which temporarily disables power-save in response to this indication, allowing the AP to transmit whatever data it has buffered for the STA / whatever data is inbound at that time. This patch does not make these AP's work reliably in PSM, but improves the chances of inbound data getting through. The side effect of this patch is increased power consumption when using a faulty AP. Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Reviewed-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com> Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_event.c')
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index ca52cdec7a8f..15f6b86f81a2 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -28,6 +28,63 @@
28#include "wl1271_ps.h" 28#include "wl1271_ps.h"
29#include "wl12xx_80211.h" 29#include "wl12xx_80211.h"
30 30
31void wl1271_pspoll_work(struct work_struct *work)
32{
33 struct delayed_work *dwork;
34 struct wl1271 *wl;
35
36 dwork = container_of(work, struct delayed_work, work);
37 wl = container_of(dwork, struct wl1271, pspoll_work);
38
39 wl1271_debug(DEBUG_EVENT, "pspoll work");
40
41 mutex_lock(&wl->mutex);
42
43 if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags))
44 goto out;
45
46 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
47 goto out;
48
49 /*
50 * if we end up here, then we were in powersave when the pspoll
51 * delivery failure occurred, and no-one changed state since, so
52 * we should go back to powersave.
53 */
54 wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, true);
55
56out:
57 mutex_unlock(&wl->mutex);
58};
59
60static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
61{
62 int delay = wl->conf.conn.ps_poll_recovery_period;
63 int ret;
64
65 wl->ps_poll_failures++;
66 if (wl->ps_poll_failures == 1)
67 wl1271_info("AP with dysfunctional ps-poll, "
68 "trying to work around it.");
69
70 /* force active mode receive data from the AP */
71 if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
72 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, true);
73 if (ret < 0)
74 return;
75 set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
76 ieee80211_queue_delayed_work(wl->hw, &wl->pspoll_work,
77 msecs_to_jiffies(delay));
78 }
79
80 /*
81 * If already in active mode, lets we should be getting data from
82 * the AP right away. If we enter PSM too fast after this, and data
83 * remains on the AP, we will get another event like this, and we'll
84 * go into active once more.
85 */
86}
87
31static int wl1271_event_scan_complete(struct wl1271 *wl, 88static int wl1271_event_scan_complete(struct wl1271 *wl,
32 struct event_mailbox *mbox) 89 struct event_mailbox *mbox)
33{ 90{
@@ -191,6 +248,9 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
191 return ret; 248 return ret;
192 } 249 }
193 250
251 if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
252 wl1271_event_pspoll_delivery_fail(wl);
253
194 if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { 254 if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
195 wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); 255 wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
196 if (wl->vif) 256 if (wl->vif)