2 * Mac80211 power management API for ST-Ericsson CW1200 drivers
4 * Copyright (c) 2011, ST-Ericsson
5 * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
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.
12 #include <linux/module.h>
13 #include <linux/if_ether.h>
20 #define CW1200_BEACON_SKIPPING_MULTIPLIER 3
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
];
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
];
34 static struct cw1200_udp_port_filter cw1200_udp_port_filter_on
= {
38 .action
= WSM_FILTER_ACTION_FILTER_OUT
,
39 .type
= WSM_FILTER_PORT_TYPE_DST
,
40 .port
= __cpu_to_le16(67), /* DHCP Bootps */
43 .action
= WSM_FILTER_ACTION_FILTER_OUT
,
44 .type
= WSM_FILTER_PORT_TYPE_DST
,
45 .port
= __cpu_to_le16(68), /* DHCP Bootpc */
50 static struct wsm_udp_port_filter_hdr cw1200_udp_port_filter_off
= {
55 #define ETH_P_WAPI 0x88B4
58 static struct cw1200_ether_type_filter cw1200_ether_type_filter_on
= {
62 .action
= WSM_FILTER_ACTION_FILTER_IN
,
63 .type
= __cpu_to_le16(ETH_P_IP
),
66 .action
= WSM_FILTER_ACTION_FILTER_IN
,
67 .type
= __cpu_to_le16(ETH_P_PAE
),
70 .action
= WSM_FILTER_ACTION_FILTER_IN
,
71 .type
= __cpu_to_le16(ETH_P_WAPI
),
74 .action
= WSM_FILTER_ACTION_FILTER_IN
,
75 .type
= __cpu_to_le16(ETH_P_ARP
),
80 static struct wsm_ether_type_filter_hdr cw1200_ether_type_filter_off
= {
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
;
94 static void cw1200_pm_stay_awake_tmo(struct timer_list
*unused
)
96 /* XXX what's the point of this ? */
99 int cw1200_pm_init(struct cw1200_pm_state
*pm
,
100 struct cw1200_common
*priv
)
102 spin_lock_init(&pm
->lock
);
104 timer_setup(&pm
->stay_awake
, cw1200_pm_stay_awake_tmo
, 0);
109 void cw1200_pm_deinit(struct cw1200_pm_state
*pm
)
111 del_timer_sync(&pm
->stay_awake
);
114 void cw1200_pm_stay_awake(struct cw1200_pm_state
*pm
,
118 spin_lock_bh(&pm
->lock
);
119 cur_tmo
= pm
->stay_awake
.expires
- jiffies
;
120 if (!timer_pending(&pm
->stay_awake
) || cur_tmo
< (long)tmo
)
121 mod_timer(&pm
->stay_awake
, jiffies
+ tmo
);
122 spin_unlock_bh(&pm
->lock
);
125 static long cw1200_suspend_work(struct delayed_work
*work
)
127 int ret
= cancel_delayed_work(work
);
130 /* Timer is pending */
131 tmo
= work
->timer
.expires
- jiffies
;
140 static int cw1200_resume_work(struct cw1200_common
*priv
,
141 struct delayed_work
*work
,
147 return queue_delayed_work(priv
->workqueue
, work
, tmo
);
150 int cw1200_can_suspend(struct cw1200_common
*priv
)
152 if (atomic_read(&priv
->bh_rx
)) {
153 wiphy_dbg(priv
->hw
->wiphy
, "Suspend interrupted.\n");
158 EXPORT_SYMBOL_GPL(cw1200_can_suspend
);
160 int cw1200_wow_suspend(struct ieee80211_hw
*hw
, struct cfg80211_wowlan
*wowlan
)
162 struct cw1200_common
*priv
= hw
->priv
;
163 struct cw1200_pm_state
*pm_state
= &priv
->pm_state
;
164 struct cw1200_suspend_state
*state
;
167 spin_lock_bh(&pm_state
->lock
);
168 ret
= timer_pending(&pm_state
->stay_awake
);
169 spin_unlock_bh(&pm_state
->lock
);
173 /* Do not suspend when datapath is not idle */
174 if (priv
->tx_queue_stats
.num_queued
)
177 /* Make sure there is no configuration requests in progress. */
178 if (!mutex_trylock(&priv
->conf_mutex
))
181 /* Ensure pending operations are done.
182 * Note also that wow_suspend must return in ~2.5sec, before
183 * watchdog is triggered.
185 if (priv
->channel_switch_in_progress
)
188 /* Do not suspend when join is pending */
189 if (priv
->join_pending
)
192 /* Do not suspend when scanning */
193 if (down_trylock(&priv
->scan
.lock
))
197 wsm_lock_tx_async(priv
);
199 /* Wait to avoid possible race with bh code.
200 * But do not wait too long...
202 if (wait_event_timeout(priv
->bh_evt_wq
,
203 !priv
->hw_bufs_used
, HZ
/ 10) <= 0)
207 wsm_set_udp_port_filter(priv
, &cw1200_udp_port_filter_on
.hdr
);
209 /* Set ethernet frame type filter */
210 wsm_set_ether_type_filter(priv
, &cw1200_ether_type_filter_on
.hdr
);
213 state
= kzalloc(sizeof(struct cw1200_suspend_state
), GFP_KERNEL
);
217 /* Change to legacy PS while going to suspend */
218 if (!priv
->vif
->p2p
&&
219 priv
->join_status
== CW1200_JOIN_STATUS_STA
&&
220 priv
->powersave_mode
.mode
!= WSM_PSM_PS
) {
221 state
->prev_ps_mode
= priv
->powersave_mode
.mode
;
222 priv
->powersave_mode
.mode
= WSM_PSM_PS
;
223 cw1200_set_pm(priv
, &priv
->powersave_mode
);
224 if (wait_event_interruptible_timeout(priv
->ps_mode_switch_done
,
225 !priv
->ps_mode_switch_in_progress
, 1*HZ
) <= 0) {
230 /* Store delayed work states. */
231 state
->bss_loss_tmo
=
232 cw1200_suspend_work(&priv
->bss_loss_work
);
234 cw1200_suspend_work(&priv
->join_timeout
);
235 state
->direct_probe
=
236 cw1200_suspend_work(&priv
->scan
.probe_work
);
238 cw1200_suspend_work(&priv
->link_id_gc_work
);
240 cancel_delayed_work_sync(&priv
->clear_recent_scan_work
);
241 atomic_set(&priv
->recent_scan
, 0);
243 /* Enable beacon skipping */
244 if (priv
->join_status
== CW1200_JOIN_STATUS_STA
&&
245 priv
->join_dtim_period
&&
246 !priv
->has_multicast_subscription
) {
247 state
->beacon_skipping
= true;
248 wsm_set_beacon_wakeup_period(priv
,
249 priv
->join_dtim_period
,
250 CW1200_BEACON_SKIPPING_MULTIPLIER
* priv
->join_dtim_period
);
253 /* Stop serving thread */
254 if (cw1200_bh_suspend(priv
))
257 ret
= timer_pending(&priv
->mcast_timeout
);
261 /* Store suspend state */
262 pm_state
->suspend_state
= state
;
264 /* Enable IRQ wake */
265 ret
= priv
->hwbus_ops
->power_mgmt(priv
->hwbus_priv
, true);
267 wiphy_err(priv
->hw
->wiphy
,
268 "PM request failed: %d. WoW is disabled.\n", ret
);
269 cw1200_wow_resume(hw
);
273 /* Force resume if event is coming from the device. */
274 if (atomic_read(&priv
->bh_rx
)) {
275 cw1200_wow_resume(hw
);
282 WARN_ON(cw1200_bh_resume(priv
));
284 cw1200_resume_work(priv
, &priv
->bss_loss_work
,
285 state
->bss_loss_tmo
);
286 cw1200_resume_work(priv
, &priv
->join_timeout
,
288 cw1200_resume_work(priv
, &priv
->scan
.probe_work
,
289 state
->direct_probe
);
290 cw1200_resume_work(priv
, &priv
->link_id_gc_work
,
295 wsm_set_udp_port_filter(priv
, &cw1200_udp_port_filter_off
);
296 wsm_set_ether_type_filter(priv
, &cw1200_ether_type_filter_off
);
299 up(&priv
->scan
.lock
);
301 mutex_unlock(&priv
->conf_mutex
);
305 int cw1200_wow_resume(struct ieee80211_hw
*hw
)
307 struct cw1200_common
*priv
= hw
->priv
;
308 struct cw1200_pm_state
*pm_state
= &priv
->pm_state
;
309 struct cw1200_suspend_state
*state
;
311 state
= pm_state
->suspend_state
;
312 pm_state
->suspend_state
= NULL
;
314 /* Disable IRQ wake */
315 priv
->hwbus_ops
->power_mgmt(priv
->hwbus_priv
, false);
317 /* Scan.lock must be released before BH is resumed other way
318 * in case when BSS_LOST command arrived the processing of the
319 * command will be delayed.
321 up(&priv
->scan
.lock
);
323 /* Resume BH thread */
324 WARN_ON(cw1200_bh_resume(priv
));
326 /* Restores previous PS mode */
327 if (!priv
->vif
->p2p
&& priv
->join_status
== CW1200_JOIN_STATUS_STA
) {
328 priv
->powersave_mode
.mode
= state
->prev_ps_mode
;
329 cw1200_set_pm(priv
, &priv
->powersave_mode
);
332 if (state
->beacon_skipping
) {
333 wsm_set_beacon_wakeup_period(priv
, priv
->beacon_int
*
334 priv
->join_dtim_period
>
335 MAX_BEACON_SKIP_TIME_MS
? 1 :
336 priv
->join_dtim_period
, 0);
337 state
->beacon_skipping
= false;
340 /* Resume delayed work */
341 cw1200_resume_work(priv
, &priv
->bss_loss_work
,
342 state
->bss_loss_tmo
);
343 cw1200_resume_work(priv
, &priv
->join_timeout
,
345 cw1200_resume_work(priv
, &priv
->scan
.probe_work
,
346 state
->direct_probe
);
347 cw1200_resume_work(priv
, &priv
->link_id_gc_work
,
350 /* Remove UDP port filter */
351 wsm_set_udp_port_filter(priv
, &cw1200_udp_port_filter_off
);
353 /* Remove ethernet frame type filter */
354 wsm_set_ether_type_filter(priv
, &cw1200_ether_type_filter_off
);
356 /* Unlock datapath */
359 /* Unlock configuration mutex */
360 mutex_unlock(&priv
->conf_mutex
);