cw1200: move under st vendor directory
[cascardo/linux.git] / drivers / net / wireless / st / 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         setup_timer(&pm->stay_awake, cw1200_pm_stay_awake_tmo,
105                     (unsigned long)pm);
106
107         return 0;
108 }
109
110 void cw1200_pm_deinit(struct cw1200_pm_state *pm)
111 {
112         del_timer_sync(&pm->stay_awake);
113 }
114
115 void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
116                           unsigned long tmo)
117 {
118         long cur_tmo;
119         spin_lock_bh(&pm->lock);
120         cur_tmo = pm->stay_awake.expires - jiffies;
121         if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo)
122                 mod_timer(&pm->stay_awake, jiffies + tmo);
123         spin_unlock_bh(&pm->lock);
124 }
125
126 static long cw1200_suspend_work(struct delayed_work *work)
127 {
128         int ret = cancel_delayed_work(work);
129         long tmo;
130         if (ret > 0) {
131                 /* Timer is pending */
132                 tmo = work->timer.expires - jiffies;
133                 if (tmo < 0)
134                         tmo = 0;
135         } else {
136                 tmo = -1;
137         }
138         return tmo;
139 }
140
141 static int cw1200_resume_work(struct cw1200_common *priv,
142                                struct delayed_work *work,
143                                unsigned long tmo)
144 {
145         if ((long)tmo < 0)
146                 return 1;
147
148         return queue_delayed_work(priv->workqueue, work, tmo);
149 }
150
151 int cw1200_can_suspend(struct cw1200_common *priv)
152 {
153         if (atomic_read(&priv->bh_rx)) {
154                 wiphy_dbg(priv->hw->wiphy, "Suspend interrupted.\n");
155                 return 0;
156         }
157         return 1;
158 }
159 EXPORT_SYMBOL_GPL(cw1200_can_suspend);
160
161 int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
162 {
163         struct cw1200_common *priv = hw->priv;
164         struct cw1200_pm_state *pm_state = &priv->pm_state;
165         struct cw1200_suspend_state *state;
166         int ret;
167
168         spin_lock_bh(&pm_state->lock);
169         ret = timer_pending(&pm_state->stay_awake);
170         spin_unlock_bh(&pm_state->lock);
171         if (ret)
172                 return -EAGAIN;
173
174         /* Do not suspend when datapath is not idle */
175         if (priv->tx_queue_stats.num_queued)
176                 return -EBUSY;
177
178         /* Make sure there is no configuration requests in progress. */
179         if (!mutex_trylock(&priv->conf_mutex))
180                 return -EBUSY;
181
182         /* Ensure pending operations are done.
183          * Note also that wow_suspend must return in ~2.5sec, before
184          * watchdog is triggered.
185          */
186         if (priv->channel_switch_in_progress)
187                 goto revert1;
188
189         /* Do not suspend when join is pending */
190         if (priv->join_pending)
191                 goto revert1;
192
193         /* Do not suspend when scanning */
194         if (down_trylock(&priv->scan.lock))
195                 goto revert1;
196
197         /* Lock TX. */
198         wsm_lock_tx_async(priv);
199
200         /* Wait to avoid possible race with bh code.
201          * But do not wait too long...
202          */
203         if (wait_event_timeout(priv->bh_evt_wq,
204                                !priv->hw_bufs_used, HZ / 10) <= 0)
205                 goto revert2;
206
207         /* Set UDP filter */
208         wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_on.hdr);
209
210         /* Set ethernet frame type filter */
211         wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_on.hdr);
212
213         /* Allocate state */
214         state = kzalloc(sizeof(struct cw1200_suspend_state), GFP_KERNEL);
215         if (!state)
216                 goto revert3;
217
218         /* Change to legacy PS while going to suspend */
219         if (!priv->vif->p2p &&
220             priv->join_status == CW1200_JOIN_STATUS_STA &&
221             priv->powersave_mode.mode != WSM_PSM_PS) {
222                 state->prev_ps_mode = priv->powersave_mode.mode;
223                 priv->powersave_mode.mode = WSM_PSM_PS;
224                 cw1200_set_pm(priv, &priv->powersave_mode);
225                 if (wait_event_interruptible_timeout(priv->ps_mode_switch_done,
226                                                      !priv->ps_mode_switch_in_progress, 1*HZ) <= 0) {
227                         goto revert4;
228                 }
229         }
230
231         /* Store delayed work states. */
232         state->bss_loss_tmo =
233                 cw1200_suspend_work(&priv->bss_loss_work);
234         state->join_tmo =
235                 cw1200_suspend_work(&priv->join_timeout);
236         state->direct_probe =
237                 cw1200_suspend_work(&priv->scan.probe_work);
238         state->link_id_gc =
239                 cw1200_suspend_work(&priv->link_id_gc_work);
240
241         cancel_delayed_work_sync(&priv->clear_recent_scan_work);
242         atomic_set(&priv->recent_scan, 0);
243
244         /* Enable beacon skipping */
245         if (priv->join_status == CW1200_JOIN_STATUS_STA &&
246             priv->join_dtim_period &&
247             !priv->has_multicast_subscription) {
248                 state->beacon_skipping = true;
249                 wsm_set_beacon_wakeup_period(priv,
250                                              priv->join_dtim_period,
251                                              CW1200_BEACON_SKIPPING_MULTIPLIER * priv->join_dtim_period);
252         }
253
254         /* Stop serving thread */
255         if (cw1200_bh_suspend(priv))
256                 goto revert5;
257
258         ret = timer_pending(&priv->mcast_timeout);
259         if (ret)
260                 goto revert6;
261
262         /* Store suspend state */
263         pm_state->suspend_state = state;
264
265         /* Enable IRQ wake */
266         ret = priv->hwbus_ops->power_mgmt(priv->hwbus_priv, true);
267         if (ret) {
268                 wiphy_err(priv->hw->wiphy,
269                           "PM request failed: %d. WoW is disabled.\n", ret);
270                 cw1200_wow_resume(hw);
271                 return -EBUSY;
272         }
273
274         /* Force resume if event is coming from the device. */
275         if (atomic_read(&priv->bh_rx)) {
276                 cw1200_wow_resume(hw);
277                 return -EAGAIN;
278         }
279
280         return 0;
281
282 revert6:
283         WARN_ON(cw1200_bh_resume(priv));
284 revert5:
285         cw1200_resume_work(priv, &priv->bss_loss_work,
286                            state->bss_loss_tmo);
287         cw1200_resume_work(priv, &priv->join_timeout,
288                            state->join_tmo);
289         cw1200_resume_work(priv, &priv->scan.probe_work,
290                            state->direct_probe);
291         cw1200_resume_work(priv, &priv->link_id_gc_work,
292                            state->link_id_gc);
293 revert4:
294         kfree(state);
295 revert3:
296         wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off);
297         wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off);
298 revert2:
299         wsm_unlock_tx(priv);
300         up(&priv->scan.lock);
301 revert1:
302         mutex_unlock(&priv->conf_mutex);
303         return -EBUSY;
304 }
305
306 int cw1200_wow_resume(struct ieee80211_hw *hw)
307 {
308         struct cw1200_common *priv = hw->priv;
309         struct cw1200_pm_state *pm_state = &priv->pm_state;
310         struct cw1200_suspend_state *state;
311
312         state = pm_state->suspend_state;
313         pm_state->suspend_state = NULL;
314
315         /* Disable IRQ wake */
316         priv->hwbus_ops->power_mgmt(priv->hwbus_priv, false);
317
318         /* Scan.lock must be released before BH is resumed other way
319          * in case when BSS_LOST command arrived the processing of the
320          * command will be delayed.
321          */
322         up(&priv->scan.lock);
323
324         /* Resume BH thread */
325         WARN_ON(cw1200_bh_resume(priv));
326
327         /* Restores previous PS mode */
328         if (!priv->vif->p2p && priv->join_status == CW1200_JOIN_STATUS_STA) {
329                 priv->powersave_mode.mode = state->prev_ps_mode;
330                 cw1200_set_pm(priv, &priv->powersave_mode);
331         }
332
333         if (state->beacon_skipping) {
334                 wsm_set_beacon_wakeup_period(priv, priv->beacon_int *
335                                              priv->join_dtim_period >
336                                              MAX_BEACON_SKIP_TIME_MS ? 1 :
337                                              priv->join_dtim_period, 0);
338                 state->beacon_skipping = false;
339         }
340
341         /* Resume delayed work */
342         cw1200_resume_work(priv, &priv->bss_loss_work,
343                            state->bss_loss_tmo);
344         cw1200_resume_work(priv, &priv->join_timeout,
345                            state->join_tmo);
346         cw1200_resume_work(priv, &priv->scan.probe_work,
347                            state->direct_probe);
348         cw1200_resume_work(priv, &priv->link_id_gc_work,
349                            state->link_id_gc);
350
351         /* Remove UDP port filter */
352         wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off);
353
354         /* Remove ethernet frame type filter */
355         wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off);
356
357         /* Unlock datapath */
358         wsm_unlock_tx(priv);
359
360         /* Unlock configuration mutex */
361         mutex_unlock(&priv->conf_mutex);
362
363         /* Free memory */
364         kfree(state);
365
366         return 0;
367 }