Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ps.c
Go to the documentation of this file.
1 /*
2  * This file is part of wl1271
3  *
4  * Copyright (C) 2008-2009 Nokia Corporation
5  *
6  * Contact: Luciano Coelho <[email protected]>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  *
22  */
23 
24 #include "ps.h"
25 #include "io.h"
26 #include "tx.h"
27 #include "debug.h"
28 
29 #define WL1271_WAKEUP_TIMEOUT 500
30 
31 #define ELP_ENTRY_DELAY 30
32 
34 {
35  struct delayed_work *dwork;
36  struct wl1271 *wl;
37  struct wl12xx_vif *wlvif;
38  int ret;
39 
40  dwork = container_of(work, struct delayed_work, work);
41  wl = container_of(dwork, struct wl1271, elp_work);
42 
43  wl1271_debug(DEBUG_PSM, "elp work");
44 
45  mutex_lock(&wl->mutex);
46 
47  if (unlikely(wl->state != WLCORE_STATE_ON))
48  goto out;
49 
50  /* our work might have been already cancelled */
52  goto out;
53 
55  goto out;
56 
57  wl12xx_for_each_wlvif(wl, wlvif) {
58  if (wlvif->bss_type == BSS_TYPE_AP_BSS)
59  goto out;
60 
61  if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
63  goto out;
64  }
65 
66  wl1271_debug(DEBUG_PSM, "chip to elp");
67  ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP);
68  if (ret < 0) {
70  goto out;
71  }
72 
74 
75 out:
76  mutex_unlock(&wl->mutex);
77 }
78 
79 /* Routines to toggle sleep mode while in ELP */
81 {
82  struct wl12xx_vif *wlvif;
83  u32 timeout;
84 
85  if (wl->sleep_auth != WL1271_PSM_ELP)
86  return;
87 
88  /* we shouldn't get consecutive sleep requests */
90  return;
91 
92  wl12xx_for_each_wlvif(wl, wlvif) {
93  if (wlvif->bss_type == BSS_TYPE_AP_BSS)
94  return;
95 
96  if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
98  return;
99  }
100 
101  timeout = ELP_ENTRY_DELAY;
103  msecs_to_jiffies(timeout));
104 }
105 
107 {
109  unsigned long flags;
110  int ret;
112  bool pending = false;
113 
114  /*
115  * we might try to wake up even if we didn't go to sleep
116  * before (e.g. on boot)
117  */
119  return 0;
120 
121  /* don't cancel_sync as it might contend for a mutex and deadlock */
123 
124  if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
125  return 0;
126 
127  wl1271_debug(DEBUG_PSM, "waking up chip from elp");
128 
129  /*
130  * The spinlock is required here to synchronize both the work and
131  * the completion variable in one entity.
132  */
133  spin_lock_irqsave(&wl->wl_lock, flags);
135  pending = true;
136  else
137  wl->elp_compl = &compl;
138  spin_unlock_irqrestore(&wl->wl_lock, flags);
139 
140  ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
141  if (ret < 0) {
143  goto err;
144  }
145 
146  if (!pending) {
149  if (ret == 0) {
150  wl1271_error("ELP wakeup timeout!");
152  ret = -ETIMEDOUT;
153  goto err;
154  } else if (ret < 0) {
155  wl1271_error("ELP wakeup completion error.");
156  goto err;
157  }
158  }
159 
161 
162  wl1271_debug(DEBUG_PSM, "wakeup time: %u ms",
163  jiffies_to_msecs(jiffies - start_time));
164  goto out;
165 
166 err:
167  spin_lock_irqsave(&wl->wl_lock, flags);
168  wl->elp_compl = NULL;
169  spin_unlock_irqrestore(&wl->wl_lock, flags);
170  return ret;
171 
172 out:
173  return 0;
174 }
175 
176 int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
178 {
179  int ret;
180  u16 timeout = wl->conf.conn.dynamic_ps_timeout;
181 
182  switch (mode) {
185  wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)",
186  mode, timeout);
187 
188  ret = wl1271_acx_wake_up_conditions(wl, wlvif,
189  wl->conf.conn.wake_up_event,
190  wl->conf.conn.listen_interval);
191  if (ret < 0) {
192  wl1271_error("couldn't set wake up conditions");
193  return ret;
194  }
195 
196  ret = wl1271_cmd_ps_mode(wl, wlvif, mode, timeout);
197  if (ret < 0)
198  return ret;
199 
200  set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
201 
202  /*
203  * enable beacon early termination.
204  * Not relevant for 5GHz and for high rates.
205  */
206  if ((wlvif->band == IEEE80211_BAND_2GHZ) &&
207  (wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) {
208  ret = wl1271_acx_bet_enable(wl, wlvif, true);
209  if (ret < 0)
210  return ret;
211  }
212  break;
213  case STATION_ACTIVE_MODE:
214  wl1271_debug(DEBUG_PSM, "leaving psm");
215 
216  /* disable beacon early termination */
217  if ((wlvif->band == IEEE80211_BAND_2GHZ) &&
218  (wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) {
219  ret = wl1271_acx_bet_enable(wl, wlvif, false);
220  if (ret < 0)
221  return ret;
222  }
223 
224  ret = wl1271_cmd_ps_mode(wl, wlvif, mode, 0);
225  if (ret < 0)
226  return ret;
227 
228  clear_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
229  break;
230  default:
231  wl1271_warning("trying to set ps to unsupported mode %d", mode);
232  ret = -EINVAL;
233  }
234 
235  return ret;
236 }
237 
238 static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
239 {
240  int i;
241  struct sk_buff *skb;
242  struct ieee80211_tx_info *info;
243  unsigned long flags;
244  int filtered[NUM_TX_QUEUES];
245 
246  /* filter all frames currently in the low level queues for this hlid */
247  for (i = 0; i < NUM_TX_QUEUES; i++) {
248  filtered[i] = 0;
249  while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
250  filtered[i]++;
251 
252  if (WARN_ON(wl12xx_is_dummy_packet(wl, skb)))
253  continue;
254 
255  info = IEEE80211_SKB_CB(skb);
257  info->status.rates[0].idx = -1;
258  ieee80211_tx_status_ni(wl->hw, skb);
259  }
260  }
261 
262  spin_lock_irqsave(&wl->wl_lock, flags);
263  for (i = 0; i < NUM_TX_QUEUES; i++)
264  wl->tx_queue_count[i] -= filtered[i];
265  spin_unlock_irqrestore(&wl->wl_lock, flags);
266 
268 }
269 
270 void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
271  u8 hlid, bool clean_queues)
272 {
273  struct ieee80211_sta *sta;
274  struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
275 
276  if (test_bit(hlid, &wl->ap_ps_map))
277  return;
278 
279  wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d "
280  "clean_queues %d", hlid, wl->links[hlid].allocated_pkts,
281  clean_queues);
282 
283  rcu_read_lock();
284  sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
285  if (!sta) {
286  wl1271_error("could not find sta %pM for starting ps",
287  wl->links[hlid].addr);
288  rcu_read_unlock();
289  return;
290  }
291 
292  ieee80211_sta_ps_transition_ni(sta, true);
293  rcu_read_unlock();
294 
295  /* do we want to filter all frames from this link's queues? */
296  if (clean_queues)
297  wl1271_ps_filter_frames(wl, hlid);
298 
299  __set_bit(hlid, &wl->ap_ps_map);
300 }
301 
302 void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
303 {
304  struct ieee80211_sta *sta;
305  struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
306 
307  if (!test_bit(hlid, &wl->ap_ps_map))
308  return;
309 
310  wl1271_debug(DEBUG_PSM, "end mac80211 PSM on hlid %d", hlid);
311 
312  __clear_bit(hlid, &wl->ap_ps_map);
313 
314  rcu_read_lock();
315  sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
316  if (!sta) {
317  wl1271_error("could not find sta %pM for ending ps",
318  wl->links[hlid].addr);
319  goto end;
320  }
321 
322  ieee80211_sta_ps_transition_ni(sta, false);
323 end:
324  rcu_read_unlock();
325 }