]>
Commit | Line | Data |
---|---|---|
f5fc0f86 LC |
1 | /* |
2 | * This file is part of wl1271 | |
3 | * | |
4 | * Copyright (C) 2008-2009 Nokia Corporation | |
5 | * | |
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | |
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 | ||
00d20100 SL |
24 | #include "ps.h" |
25 | #include "io.h" | |
b622d992 | 26 | #include "tx.h" |
0f4e3122 | 27 | #include "debug.h" |
f5fc0f86 LC |
28 | |
29 | #define WL1271_WAKEUP_TIMEOUT 500 | |
30 | ||
ab2c4f37 | 31 | #define ELP_ENTRY_DELAY 30 |
0c7cc7f2 | 32 | #define ELP_ENTRY_DELAY_FORCE_PS 5 |
1ab0f212 | 33 | |
37b70a81 | 34 | void wl1271_elp_work(struct work_struct *work) |
f5fc0f86 | 35 | { |
37b70a81 JO |
36 | struct delayed_work *dwork; |
37 | struct wl1271 *wl; | |
c29bb001 | 38 | struct wl12xx_vif *wlvif; |
b0f0ad39 | 39 | int ret; |
37b70a81 | 40 | |
61383412 | 41 | dwork = to_delayed_work(work); |
37b70a81 JO |
42 | wl = container_of(dwork, struct wl1271, elp_work); |
43 | ||
44 | wl1271_debug(DEBUG_PSM, "elp work"); | |
45 | ||
46 | mutex_lock(&wl->mutex); | |
47 | ||
4cc53383 | 48 | if (unlikely(wl->state != WLCORE_STATE_ON)) |
8c7f4f31 JO |
49 | goto out; |
50 | ||
a665d6e2 EP |
51 | /* our work might have been already cancelled */ |
52 | if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) | |
53 | goto out; | |
54 | ||
c29bb001 | 55 | if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) |
37b70a81 | 56 | goto out; |
f5fc0f86 | 57 | |
c29bb001 | 58 | wl12xx_for_each_wlvif(wl, wlvif) { |
5c0dc2fc | 59 | if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && |
a0c7b782 | 60 | test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) |
c29bb001 EP |
61 | goto out; |
62 | } | |
63 | ||
37b70a81 | 64 | wl1271_debug(DEBUG_PSM, "chip to elp"); |
b0f0ad39 IY |
65 | ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP); |
66 | if (ret < 0) { | |
67 | wl12xx_queue_recovery_work(wl); | |
68 | goto out; | |
69 | } | |
70 | ||
71449f8d | 71 | set_bit(WL1271_FLAG_IN_ELP, &wl->flags); |
37b70a81 JO |
72 | |
73 | out: | |
74 | mutex_unlock(&wl->mutex); | |
75 | } | |
76 | ||
37b70a81 JO |
77 | /* Routines to toggle sleep mode while in ELP */ |
78 | void wl1271_ps_elp_sleep(struct wl1271 *wl) | |
79 | { | |
c29bb001 | 80 | struct wl12xx_vif *wlvif; |
1ab0f212 | 81 | u32 timeout; |
c29bb001 | 82 | |
e7441ce4 YS |
83 | /* We do not enter elp sleep in PLT mode */ |
84 | if (wl->plt) | |
85 | return; | |
86 | ||
26b5858a | 87 | if (wl->sleep_auth != WL1271_PSM_ELP) |
441101f6 LC |
88 | return; |
89 | ||
a665d6e2 EP |
90 | /* we shouldn't get consecutive sleep requests */ |
91 | if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) | |
92 | return; | |
93 | ||
c29bb001 | 94 | wl12xx_for_each_wlvif(wl, wlvif) { |
5c0dc2fc | 95 | if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && |
a0c7b782 | 96 | test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) |
c29bb001 EP |
97 | return; |
98 | } | |
a665d6e2 | 99 | |
0c7cc7f2 IC |
100 | timeout = wl->conf.conn.forced_ps ? |
101 | ELP_ENTRY_DELAY_FORCE_PS : ELP_ENTRY_DELAY; | |
a665d6e2 | 102 | ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, |
1ab0f212 | 103 | msecs_to_jiffies(timeout)); |
f5fc0f86 | 104 | } |
e7d32324 | 105 | EXPORT_SYMBOL_GPL(wl1271_ps_elp_sleep); |
f5fc0f86 | 106 | |
a620865e | 107 | int wl1271_ps_elp_wakeup(struct wl1271 *wl) |
f5fc0f86 LC |
108 | { |
109 | DECLARE_COMPLETION_ONSTACK(compl); | |
110 | unsigned long flags; | |
111 | int ret; | |
2baf53c6 | 112 | unsigned long start_time = jiffies; |
f5fc0f86 LC |
113 | bool pending = false; |
114 | ||
a665d6e2 EP |
115 | /* |
116 | * we might try to wake up even if we didn't go to sleep | |
117 | * before (e.g. on boot) | |
118 | */ | |
119 | if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)) | |
120 | return 0; | |
121 | ||
122 | /* don't cancel_sync as it might contend for a mutex and deadlock */ | |
123 | cancel_delayed_work(&wl->elp_work); | |
124 | ||
71449f8d | 125 | if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) |
f5fc0f86 LC |
126 | return 0; |
127 | ||
128 | wl1271_debug(DEBUG_PSM, "waking up chip from elp"); | |
129 | ||
130 | /* | |
131 | * The spinlock is required here to synchronize both the work and | |
132 | * the completion variable in one entity. | |
133 | */ | |
134 | spin_lock_irqsave(&wl->wl_lock, flags); | |
a620865e | 135 | if (test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) |
f5fc0f86 LC |
136 | pending = true; |
137 | else | |
138 | wl->elp_compl = &compl; | |
139 | spin_unlock_irqrestore(&wl->wl_lock, flags); | |
140 | ||
b0f0ad39 IY |
141 | ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); |
142 | if (ret < 0) { | |
143 | wl12xx_queue_recovery_work(wl); | |
144 | goto err; | |
145 | } | |
f5fc0f86 LC |
146 | |
147 | if (!pending) { | |
148 | ret = wait_for_completion_timeout( | |
149 | &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); | |
150 | if (ret == 0) { | |
151 | wl1271_error("ELP wakeup timeout!"); | |
baacb9ae | 152 | wl12xx_queue_recovery_work(wl); |
f5fc0f86 LC |
153 | ret = -ETIMEDOUT; |
154 | goto err; | |
f5fc0f86 LC |
155 | } |
156 | } | |
157 | ||
71449f8d | 158 | clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); |
f5fc0f86 LC |
159 | |
160 | wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", | |
161 | jiffies_to_msecs(jiffies - start_time)); | |
162 | goto out; | |
163 | ||
164 | err: | |
165 | spin_lock_irqsave(&wl->wl_lock, flags); | |
166 | wl->elp_compl = NULL; | |
167 | spin_unlock_irqrestore(&wl->wl_lock, flags); | |
168 | return ret; | |
169 | ||
170 | out: | |
171 | return 0; | |
172 | } | |
e7d32324 | 173 | EXPORT_SYMBOL_GPL(wl1271_ps_elp_wakeup); |
f5fc0f86 | 174 | |
0603d891 | 175 | int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
248a0018 | 176 | enum wl1271_cmd_ps_mode mode) |
f5fc0f86 LC |
177 | { |
178 | int ret; | |
f1d63a59 | 179 | u16 timeout = wl->conf.conn.dynamic_ps_timeout; |
f5fc0f86 LC |
180 | |
181 | switch (mode) { | |
f1d63a59 | 182 | case STATION_AUTO_PS_MODE: |
5c0dc2fc | 183 | case STATION_POWER_SAVE_MODE: |
f1d63a59 ES |
184 | wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)", |
185 | mode, timeout); | |
1922167b | 186 | |
dae728fe ES |
187 | ret = wl1271_acx_wake_up_conditions(wl, wlvif, |
188 | wl->conf.conn.wake_up_event, | |
189 | wl->conf.conn.listen_interval); | |
03f06b7e JO |
190 | if (ret < 0) { |
191 | wl1271_error("couldn't set wake up conditions"); | |
192 | return ret; | |
193 | } | |
194 | ||
f1d63a59 | 195 | ret = wl1271_cmd_ps_mode(wl, wlvif, mode, timeout); |
f5fc0f86 LC |
196 | if (ret < 0) |
197 | return ret; | |
198 | ||
5c0dc2fc | 199 | set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags); |
ed471d34 | 200 | |
e832837b VG |
201 | /* |
202 | * enable beacon early termination. | |
203 | * Not relevant for 5GHz and for high rates. | |
204 | */ | |
57fbcce3 | 205 | if ((wlvif->band == NL80211_BAND_2GHZ) && |
e832837b | 206 | (wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) { |
ed471d34 ES |
207 | ret = wl1271_acx_bet_enable(wl, wlvif, true); |
208 | if (ret < 0) | |
209 | return ret; | |
210 | } | |
f5fc0f86 LC |
211 | break; |
212 | case STATION_ACTIVE_MODE: | |
f5fc0f86 | 213 | wl1271_debug(DEBUG_PSM, "leaving psm"); |
f5fc0f86 | 214 | |
11f70f97 | 215 | /* disable beacon early termination */ |
57fbcce3 | 216 | if ((wlvif->band == NL80211_BAND_2GHZ) && |
e832837b | 217 | (wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) { |
0603d891 | 218 | ret = wl1271_acx_bet_enable(wl, wlvif, false); |
0e44eb20 SL |
219 | if (ret < 0) |
220 | return ret; | |
221 | } | |
11f70f97 | 222 | |
f1d63a59 | 223 | ret = wl1271_cmd_ps_mode(wl, wlvif, mode, 0); |
f5fc0f86 LC |
224 | if (ret < 0) |
225 | return ret; | |
226 | ||
5c0dc2fc | 227 | clear_bit(WLVIF_FLAG_IN_PS, &wlvif->flags); |
f5fc0f86 | 228 | break; |
f1d63a59 ES |
229 | default: |
230 | wl1271_warning("trying to set ps to unsupported mode %d", mode); | |
231 | ret = -EINVAL; | |
f5fc0f86 LC |
232 | } |
233 | ||
234 | return ret; | |
235 | } | |
b622d992 AN |
236 | |
237 | static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) | |
238 | { | |
f1a46384 | 239 | int i; |
b622d992 AN |
240 | struct sk_buff *skb; |
241 | struct ieee80211_tx_info *info; | |
242 | unsigned long flags; | |
f1a46384 | 243 | int filtered[NUM_TX_QUEUES]; |
8591d424 | 244 | struct wl1271_link *lnk = &wl->links[hlid]; |
b622d992 | 245 | |
f8e0af6b | 246 | /* filter all frames currently in the low level queues for this hlid */ |
b622d992 | 247 | for (i = 0; i < NUM_TX_QUEUES; i++) { |
f1a46384 | 248 | filtered[i] = 0; |
8591d424 | 249 | while ((skb = skb_dequeue(&lnk->tx_queue[i]))) { |
f8e0af6b AN |
250 | filtered[i]++; |
251 | ||
252 | if (WARN_ON(wl12xx_is_dummy_packet(wl, skb))) | |
253 | continue; | |
254 | ||
b622d992 AN |
255 | info = IEEE80211_SKB_CB(skb); |
256 | info->flags |= IEEE80211_TX_STAT_TX_FILTERED; | |
257 | info->status.rates[0].idx = -1; | |
c27d3acc | 258 | ieee80211_tx_status_ni(wl->hw, skb); |
b622d992 AN |
259 | } |
260 | } | |
261 | ||
262 | spin_lock_irqsave(&wl->wl_lock, flags); | |
8591d424 | 263 | for (i = 0; i < NUM_TX_QUEUES; i++) { |
f1a46384 | 264 | wl->tx_queue_count[i] -= filtered[i]; |
8591d424 AN |
265 | if (lnk->wlvif) |
266 | lnk->wlvif->tx_queue_count[i] -= filtered[i]; | |
267 | } | |
b622d992 AN |
268 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
269 | ||
270 | wl1271_handle_tx_low_watermark(wl); | |
271 | } | |
272 | ||
6e8cd331 EP |
273 | void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
274 | u8 hlid, bool clean_queues) | |
b622d992 AN |
275 | { |
276 | struct ieee80211_sta *sta; | |
6e8cd331 | 277 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); |
b622d992 | 278 | |
7a536265 AN |
279 | if (WARN_ON_ONCE(wlvif->bss_type != BSS_TYPE_AP_BSS)) |
280 | return; | |
281 | ||
282 | if (!test_bit(hlid, wlvif->ap.sta_hlid_map) || | |
283 | test_bit(hlid, &wl->ap_ps_map)) | |
b622d992 AN |
284 | return; |
285 | ||
9b17f1b3 AN |
286 | wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d " |
287 | "clean_queues %d", hlid, wl->links[hlid].allocated_pkts, | |
b622d992 AN |
288 | clean_queues); |
289 | ||
290 | rcu_read_lock(); | |
6e8cd331 | 291 | sta = ieee80211_find_sta(vif, wl->links[hlid].addr); |
b622d992 AN |
292 | if (!sta) { |
293 | wl1271_error("could not find sta %pM for starting ps", | |
294 | wl->links[hlid].addr); | |
295 | rcu_read_unlock(); | |
296 | return; | |
297 | } | |
298 | ||
299 | ieee80211_sta_ps_transition_ni(sta, true); | |
300 | rcu_read_unlock(); | |
301 | ||
302 | /* do we want to filter all frames from this link's queues? */ | |
303 | if (clean_queues) | |
304 | wl1271_ps_filter_frames(wl, hlid); | |
305 | ||
306 | __set_bit(hlid, &wl->ap_ps_map); | |
307 | } | |
308 | ||
6e8cd331 | 309 | void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) |
b622d992 AN |
310 | { |
311 | struct ieee80211_sta *sta; | |
6e8cd331 | 312 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); |
b622d992 AN |
313 | |
314 | if (!test_bit(hlid, &wl->ap_ps_map)) | |
315 | return; | |
316 | ||
317 | wl1271_debug(DEBUG_PSM, "end mac80211 PSM on hlid %d", hlid); | |
318 | ||
319 | __clear_bit(hlid, &wl->ap_ps_map); | |
320 | ||
321 | rcu_read_lock(); | |
6e8cd331 | 322 | sta = ieee80211_find_sta(vif, wl->links[hlid].addr); |
b622d992 AN |
323 | if (!sta) { |
324 | wl1271_error("could not find sta %pM for ending ps", | |
325 | wl->links[hlid].addr); | |
326 | goto end; | |
327 | } | |
328 | ||
329 | ieee80211_sta_ps_transition_ni(sta, false); | |
330 | end: | |
331 | rcu_read_unlock(); | |
332 | } |