]> Pileus Git - ~andy/linux/blob - drivers/net/wireless/cw1200/pm.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec...
[~andy/linux] / drivers / net / wireless / cw1200 / pm.c
1 /*
2  * Mac80211 power management API for ST-Ericsson CW1200 drivers
3  *
4  * Copyright (c) 2011, ST-Ericsson
5  * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <linux/module.h>
13 #include <linux/if_ether.h>
14 #include "cw1200.h"
15 #include "pm.h"
16 #include "sta.h"
17 #include "bh.h"
18 #include "hwbus.h"
19
20 #define CW1200_BEACON_SKIPPING_MULTIPLIER 3
21
22 struct cw1200_udp_port_filter {
23         struct wsm_udp_port_filter_hdr hdr;
24         /* Up to 4 filters are allowed. */
25         struct wsm_udp_port_filter filters[WSM_MAX_FILTER_ELEMENTS];
26 } __packed;
27
28 struct cw1200_ether_type_filter {
29         struct wsm_ether_type_filter_hdr hdr;
30         /* Up to 4 filters are allowed. */
31         struct wsm_ether_type_filter filters[WSM_MAX_FILTER_ELEMENTS];
32 } __packed;
33
34 static struct cw1200_udp_port_filter cw1200_udp_port_filter_on = {
35         .hdr.num = 2,
36         .filters = {
37                 [0] = {
38                         .action = WSM_FILTER_ACTION_FILTER_OUT,
39                         .type = WSM_FILTER_PORT_TYPE_DST,
40                         .port = __cpu_to_le16(67), /* DHCP Bootps */
41                 },
42                 [1] = {
43                         .action = WSM_FILTER_ACTION_FILTER_OUT,
44                         .type = WSM_FILTER_PORT_TYPE_DST,
45                         .port = __cpu_to_le16(68), /* DHCP Bootpc */
46                 },
47         }
48 };
49
50 static struct wsm_udp_port_filter_hdr cw1200_udp_port_filter_off = {
51         .num = 0,
52 };
53
54 #ifndef ETH_P_WAPI
55 #define ETH_P_WAPI     0x88B4
56 #endif
57
58 static struct cw1200_ether_type_filter cw1200_ether_type_filter_on = {
59         .hdr.num = 4,
60         .filters = {
61                 [0] = {
62                         .action = WSM_FILTER_ACTION_FILTER_IN,
63                         .type = __cpu_to_le16(ETH_P_IP),
64                 },
65                 [1] = {
66                         .action = WSM_FILTER_ACTION_FILTER_IN,
67                         .type = __cpu_to_le16(ETH_P_PAE),
68                 },
69                 [2] = {
70                         .action = WSM_FILTER_ACTION_FILTER_IN,
71                         .type = __cpu_to_le16(ETH_P_WAPI),
72                 },
73                 [3] = {
74                         .action = WSM_FILTER_ACTION_FILTER_IN,
75                         .type = __cpu_to_le16(ETH_P_ARP),
76                 },
77         },
78 };
79
80 static struct wsm_ether_type_filter_hdr cw1200_ether_type_filter_off = {
81         .num = 0,
82 };
83
84 /* private */
85 struct cw1200_suspend_state {
86         unsigned long bss_loss_tmo;
87         unsigned long join_tmo;
88         unsigned long direct_probe;
89         unsigned long link_id_gc;
90         bool beacon_skipping;
91         u8 prev_ps_mode;
92 };
93
94 static void cw1200_pm_stay_awake_tmo(unsigned long arg)
95 {
96         /* XXX what's the point of this ? */
97 }
98
99 int cw1200_pm_init(struct cw1200_pm_state *pm,
100                    struct cw1200_common *priv)
101 {
102         spin_lock_init(&pm->lock);
103
104         init_timer(&pm->stay_awake);
105         pm->stay_awake.data = (unsigned long)pm;
106         pm->stay_awake.function = cw1200_pm_stay_awake_tmo;
107
108         return 0;
109 }
110
111 void cw1200_pm_deinit(struct cw1200_pm_state *pm)
112 {
113         del_timer_sync(&pm->stay_awake);
114 }
115
116 void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
117                           unsigned long tmo)
118 {
119         long cur_tmo;
120         spin_lock_bh(&pm->lock);
121         cur_tmo = pm->stay_awake.expires - jiffies;
122         if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo)
123                 mod_timer(&pm->stay_awake, jiffies + tmo);
124         spin_unlock_bh(&pm->lock);
125 }
126
127 static long cw1200_suspend_work(struct delayed_work *work)
128 {
129         int ret = cancel_delayed_work(work);
130         long tmo;
131         if (ret > 0) {
132                 /* Timer is pending */
133                 tmo = work->timer.expires - jiffies;
134                 if (tmo < 0)
135                         tmo = 0;
136         } else {
137                 tmo = -1;
138         }
139         return tmo;
140 }
141
142 static int cw1200_resume_work(struct cw1200_common *priv,
143                                struct delayed_work *work,
144                                unsigned long tmo)
145 {
146         if ((long)tmo < 0)
147                 return 1;
148
149         return queue_delayed_work(priv->workqueue, work, tmo);
150 }
151
152 int cw1200_can_suspend(struct cw1200_common *priv)
153 {
154         if (atomic_read(&priv->bh_rx)) {
155                 wiphy_dbg(priv->hw->wiphy, "Suspend interrupted.\n");
156                 return 0;
157         }
158         return 1;
159 }
160 EXPORT_SYMBOL_GPL(cw1200_can_suspend);
161
162 int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
163 {
164         struct cw1200_common *priv = hw->priv;
165         struct cw1200_pm_state *pm_state = &priv->pm_state;
166         struct cw1200_suspend_state *state;
167         int ret;
168
169         spin_lock_bh(&pm_state->lock);
170         ret = timer_pending(&pm_state->stay_awake);
171         spin_unlock_bh(&pm_state->lock);
172         if (ret)
173                 return -EAGAIN;
174
175         /* Do not suspend when datapath is not idle */
176         if (priv->tx_queue_stats.num_queued)
177                 return -EBUSY;
178
179         /* Make sure there is no configuration requests in progress. */
180         if (!mutex_trylock(&priv->conf_mutex))
181                 return -EBUSY;
182
183         /* Ensure pending operations are done.
184          * Note also that wow_suspend must return in ~2.5sec, before
185          * watchdog is triggered.
186          */
187         if (priv->channel_switch_in_progress)
188                 goto revert1;
189
190         /* Do not suspend when join is pending */
191         if (priv->join_pending)
192                 goto revert1;
193
194         /* Do not suspend when scanning */
195         if (down_trylock(&priv->scan.lock))
196                 goto revert1;
197
198         /* Lock TX. */
199         wsm_lock_tx_async(priv);
200
201         /* Wait to avoid possible race with bh code.
202          * But do not wait too long...
203          */
204         if (wait_event_timeout(priv->bh_evt_wq,
205                                !priv->hw_bufs_used, HZ / 10) <= 0)
206                 goto revert2;
207
208         /* Set UDP filter */
209         wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_on.hdr);
210
211         /* Set ethernet frame type filter */
212         wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_on.hdr);
213
214         /* Allocate state */
215         state = kzalloc(sizeof(struct cw1200_suspend_state), GFP_KERNEL);
216         if (!state)
217                 goto revert3;
218
219         /* Change to legacy PS while going to suspend */
220         if (!priv->vif->p2p &&
221             priv->join_status == CW1200_JOIN_STATUS_STA &&
222             priv->powersave_mode.mode != WSM_PSM_PS) {
223                 state->prev_ps_mode = priv->powersave_mode.mode;
224                 priv->powersave_mode.mode = WSM_PSM_PS;
225                 cw1200_set_pm(priv, &priv->powersave_mode);
226                 if (wait_event_interruptible_timeout(priv->ps_mode_switch_done,
227                                                      !priv->ps_mode_switch_in_progress, 1*HZ) <= 0) {
228                         goto revert4;
229                 }
230         }
231
232         /* Store delayed work states. */
233         state->bss_loss_tmo =
234                 cw1200_suspend_work(&priv->bss_loss_work);
235         state->join_tmo =
236                 cw1200_suspend_work(&priv->join_timeout);
237         state->direct_probe =
238                 cw1200_suspend_work(&priv->scan.probe_work);
239         state->link_id_gc =
240                 cw1200_suspend_work(&priv->link_id_gc_work);
241
242         cancel_delayed_work_sync(&priv->clear_recent_scan_work);
243         atomic_set(&priv->recent_scan, 0);
244
245         /* Enable beacon skipping */
246         if (priv->join_status == CW1200_JOIN_STATUS_STA &&
247             priv->join_dtim_period &&
248             !priv->has_multicast_subscription) {
249                 state->beacon_skipping = true;
250                 wsm_set_beacon_wakeup_period(priv,
251                                              priv->join_dtim_period,
252                                              CW1200_BEACON_SKIPPING_MULTIPLIER * priv->join_dtim_period);
253         }
254
255         /* Stop serving thread */
256         if (cw1200_bh_suspend(priv))
257                 goto revert5;
258
259         ret = timer_pending(&priv->mcast_timeout);
260         if (ret)
261                 goto revert6;
262
263         /* Store suspend state */
264         pm_state->suspend_state = state;
265
266         /* Enable IRQ wake */
267         ret = priv->hwbus_ops->power_mgmt(priv->hwbus_priv, true);
268         if (ret) {
269                 wiphy_err(priv->hw->wiphy,
270                           "PM request failed: %d. WoW is disabled.\n", ret);
271                 cw1200_wow_resume(hw);
272                 return -EBUSY;
273         }
274
275         /* Force resume if event is coming from the device. */
276         if (atomic_read(&priv->bh_rx)) {
277                 cw1200_wow_resume(hw);
278                 return -EAGAIN;
279         }
280
281         return 0;
282
283 revert6:
284         WARN_ON(cw1200_bh_resume(priv));
285 revert5:
286         cw1200_resume_work(priv, &priv->bss_loss_work,
287                            state->bss_loss_tmo);
288         cw1200_resume_work(priv, &priv->join_timeout,
289                            state->join_tmo);
290         cw1200_resume_work(priv, &priv->scan.probe_work,
291                            state->direct_probe);
292         cw1200_resume_work(priv, &priv->link_id_gc_work,
293                            state->link_id_gc);
294 revert4:
295         kfree(state);
296 revert3:
297         wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off);
298         wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off);
299 revert2:
300         wsm_unlock_tx(priv);
301         up(&priv->scan.lock);
302 revert1:
303         mutex_unlock(&priv->conf_mutex);
304         return -EBUSY;
305 }
306
307 int cw1200_wow_resume(struct ieee80211_hw *hw)
308 {
309         struct cw1200_common *priv = hw->priv;
310         struct cw1200_pm_state *pm_state = &priv->pm_state;
311         struct cw1200_suspend_state *state;
312
313         state = pm_state->suspend_state;
314         pm_state->suspend_state = NULL;
315
316         /* Disable IRQ wake */
317         priv->hwbus_ops->power_mgmt(priv->hwbus_priv, false);
318
319         /* Scan.lock must be released before BH is resumed other way
320          * in case when BSS_LOST command arrived the processing of the
321          * command will be delayed.
322          */
323         up(&priv->scan.lock);
324
325         /* Resume BH thread */
326         WARN_ON(cw1200_bh_resume(priv));
327
328         /* Restores previous PS mode */
329         if (!priv->vif->p2p && priv->join_status == CW1200_JOIN_STATUS_STA) {
330                 priv->powersave_mode.mode = state->prev_ps_mode;
331                 cw1200_set_pm(priv, &priv->powersave_mode);
332         }
333
334         if (state->beacon_skipping) {
335                 wsm_set_beacon_wakeup_period(priv, priv->beacon_int *
336                                              priv->join_dtim_period >
337                                              MAX_BEACON_SKIP_TIME_MS ? 1 :
338                                              priv->join_dtim_period, 0);
339                 state->beacon_skipping = false;
340         }
341
342         /* Resume delayed work */
343         cw1200_resume_work(priv, &priv->bss_loss_work,
344                            state->bss_loss_tmo);
345         cw1200_resume_work(priv, &priv->join_timeout,
346                            state->join_tmo);
347         cw1200_resume_work(priv, &priv->scan.probe_work,
348                            state->direct_probe);
349         cw1200_resume_work(priv, &priv->link_id_gc_work,
350                            state->link_id_gc);
351
352         /* Remove UDP port filter */
353         wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off);
354
355         /* Remove ethernet frame type filter */
356         wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off);
357
358         /* Unlock datapath */
359         wsm_unlock_tx(priv);
360
361         /* Unlock configuration mutex */
362         mutex_unlock(&priv->conf_mutex);
363
364         /* Free memory */
365         kfree(state);
366
367         return 0;
368 }