summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/ps.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/wl12xx/ps.c')
-rw-r--r--drivers/net/wireless/wl12xx/ps.c54
1 files changed, 37 insertions, 17 deletions
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index 971f13e792d..3548377ab9c 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -43,6 +43,10 @@ void wl1271_elp_work(struct work_struct *work)
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
+ /* our work might have been already cancelled */
+ if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
+ goto out;
+
if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
(!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
!test_bit(WL1271_FLAG_IDLE, &wl->flags)))
@@ -61,12 +65,16 @@ out:
/* Routines to toggle sleep mode while in ELP */
void wl1271_ps_elp_sleep(struct wl1271 *wl)
{
- if (test_bit(WL1271_FLAG_PSM, &wl->flags) ||
- test_bit(WL1271_FLAG_IDLE, &wl->flags)) {
- cancel_delayed_work(&wl->elp_work);
- ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
- msecs_to_jiffies(ELP_ENTRY_DELAY));
- }
+ /* we shouldn't get consecutive sleep requests */
+ if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
+ return;
+
+ if (!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
+ !test_bit(WL1271_FLAG_IDLE, &wl->flags))
+ return;
+
+ ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
+ msecs_to_jiffies(ELP_ENTRY_DELAY));
}
int wl1271_ps_elp_wakeup(struct wl1271 *wl)
@@ -77,6 +85,16 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
u32 start_time = jiffies;
bool pending = false;
+ /*
+ * we might try to wake up even if we didn't go to sleep
+ * before (e.g. on boot)
+ */
+ if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))
+ return 0;
+
+ /* don't cancel_sync as it might contend for a mutex and deadlock */
+ cancel_delayed_work(&wl->elp_work);
+
if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
return 0;
@@ -100,7 +118,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
&compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
if (ret == 0) {
wl1271_error("ELP wakeup timeout!");
- ieee80211_queue_work(wl->hw, &wl->recovery_work);
+ wl12xx_queue_recovery_work(wl);
ret = -ETIMEDOUT;
goto err;
} else if (ret < 0) {
@@ -149,14 +167,13 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
case STATION_ACTIVE_MODE:
default:
wl1271_debug(DEBUG_PSM, "leaving psm");
- ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
- return ret;
/* disable beacon early termination */
- ret = wl1271_acx_bet_enable(wl, false);
- if (ret < 0)
- return ret;
+ if (wl->band == IEEE80211_BAND_2GHZ) {
+ ret = wl1271_acx_bet_enable(wl, false);
+ if (ret < 0)
+ return ret;
+ }
/* disable beacon filtering */
ret = wl1271_acx_beacon_filter_opt(wl, false);
@@ -176,24 +193,27 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
{
- int i, filtered = 0;
+ int i;
struct sk_buff *skb;
struct ieee80211_tx_info *info;
unsigned long flags;
+ int filtered[NUM_TX_QUEUES];
/* filter all frames currently the low level queus for this hlid */
for (i = 0; i < NUM_TX_QUEUES; i++) {
+ filtered[i] = 0;
while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
info = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
info->status.rates[0].idx = -1;
- ieee80211_tx_status(wl->hw, skb);
- filtered++;
+ ieee80211_tx_status_ni(wl->hw, skb);
+ filtered[i]++;
}
}
spin_lock_irqsave(&wl->wl_lock, flags);
- wl->tx_queue_count -= filtered;
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ wl->tx_queue_count[i] -= filtered[i];
spin_unlock_irqrestore(&wl->wl_lock, flags);
wl1271_handle_tx_low_watermark(wl);