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(unsigned long arg
)
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 init_timer(&pm
->stay_awake
);
105 pm
->stay_awake
.data
= (unsigned long)pm
;
106 pm
->stay_awake
.function
= cw1200_pm_stay_awake_tmo
;
111 void cw1200_pm_deinit(struct cw1200_pm_state
*pm
)
113 del_timer_sync(&pm
->stay_awake
);
116 void cw1200_pm_stay_awake(struct cw1200_pm_state
*pm
,
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
);
127 static long cw1200_suspend_work(struct delayed_work
*work
)
129 int ret
= cancel_delayed_work(work
);
132 /* Timer is pending */
133 tmo
= work
->timer
.expires
- jiffies
;
142 static int cw1200_resume_work(struct cw1200_common
*priv
,
143 struct delayed_work
*work
,
149 return queue_delayed_work(priv
->workqueue
, work
, tmo
);
152 int cw1200_can_suspend(struct cw1200_common
*priv
)
154 if (atomic_read(&priv
->bh_rx
)) {
155 wiphy_dbg(priv
->hw
->wiphy
, "Suspend interrupted.\n");
160 EXPORT_SYMBOL_GPL(cw1200_can_suspend
);
162 int cw1200_wow_suspend(struct ieee80211_hw
*hw
, struct cfg80211_wowlan
*wowlan
)
164 struct cw1200_common
*priv
= hw
->priv
;
165 struct cw1200_pm_state
*pm_state
= &priv
->pm_state
;
166 struct cw1200_suspend_state
*state
;
169 spin_lock_bh(&pm_state
->lock
);
170 ret
= timer_pending(&pm_state
->stay_awake
);
171 spin_unlock_bh(&pm_state
->lock
);
175 /* Do not suspend when datapath is not idle */
176 if (priv
->tx_queue_stats
.num_queued
)
179 /* Make sure there is no configuration requests in progress. */
180 if (!mutex_trylock(&priv
->conf_mutex
))
183 /* Ensure pending operations are done.
184 * Note also that wow_suspend must return in ~2.5sec, before
185 * watchdog is triggered.
187 if (priv
->channel_switch_in_progress
)
190 /* Do not suspend when join is pending */
191 if (priv
->join_pending
)
194 /* Do not suspend when scanning */
195 if (down_trylock(&priv
->scan
.lock
))
199 wsm_lock_tx_async(priv
);
201 /* Wait to avoid possible race with bh code.
202 * But do not wait too long...
204 if (wait_event_timeout(priv
->bh_evt_wq
,
205 !priv
->hw_bufs_used
, HZ
/ 10) <= 0)
209 wsm_set_udp_port_filter(priv
, &cw1200_udp_port_filter_on
.hdr
);
211 /* Set ethernet frame type filter */
212 wsm_set_ether_type_filter(priv
, &cw1200_ether_type_filter_on
.hdr
);
215 state
= kzalloc(sizeof(struct cw1200_suspend_state
), GFP_KERNEL
);
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) {
232 /* Store delayed work states. */
233 state
->bss_loss_tmo
=
234 cw1200_suspend_work(&priv
->bss_loss_work
);
236 cw1200_suspend_work(&priv
->join_timeout
);
237 state
->direct_probe
=
238 cw1200_suspend_work(&priv
->scan
.probe_work
);
240 cw1200_suspend_work(&priv
->link_id_gc_work
);
242 cancel_delayed_work_sync(&priv
->clear_recent_scan_work
);
243 atomic_set(&priv
->recent_scan
, 0);
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
);
255 /* Stop serving thread */
256 if (cw1200_bh_suspend(priv
))
259 ret
= timer_pending(&priv
->mcast_timeout
);
263 /* Store suspend state */
264 pm_state
->suspend_state
= state
;
266 /* Enable IRQ wake */
267 ret
= priv
->hwbus_ops
->power_mgmt(priv
->hwbus_priv
, true);
269 wiphy_err(priv
->hw
->wiphy
,
270 "PM request failed: %d. WoW is disabled.\n", ret
);
271 cw1200_wow_resume(hw
);
275 /* Force resume if event is coming from the device. */
276 if (atomic_read(&priv
->bh_rx
)) {
277 cw1200_wow_resume(hw
);
284 WARN_ON(cw1200_bh_resume(priv
));
286 cw1200_resume_work(priv
, &priv
->bss_loss_work
,
287 state
->bss_loss_tmo
);
288 cw1200_resume_work(priv
, &priv
->join_timeout
,
290 cw1200_resume_work(priv
, &priv
->scan
.probe_work
,
291 state
->direct_probe
);
292 cw1200_resume_work(priv
, &priv
->link_id_gc_work
,
296 wsm_set_udp_port_filter(priv
, &cw1200_udp_port_filter_off
);
297 wsm_set_ether_type_filter(priv
, &cw1200_ether_type_filter_off
);
300 up(&priv
->scan
.lock
);
302 mutex_unlock(&priv
->conf_mutex
);
306 int cw1200_wow_resume(struct ieee80211_hw
*hw
)
308 struct cw1200_common
*priv
= hw
->priv
;
309 struct cw1200_pm_state
*pm_state
= &priv
->pm_state
;
310 struct cw1200_suspend_state
*state
;
312 state
= pm_state
->suspend_state
;
313 pm_state
->suspend_state
= NULL
;
315 /* Disable IRQ wake */
316 priv
->hwbus_ops
->power_mgmt(priv
->hwbus_priv
, false);
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.
322 up(&priv
->scan
.lock
);
324 /* Resume BH thread */
325 WARN_ON(cw1200_bh_resume(priv
));
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
);
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;
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
,
346 cw1200_resume_work(priv
, &priv
->scan
.probe_work
,
347 state
->direct_probe
);
348 cw1200_resume_work(priv
, &priv
->link_id_gc_work
,
351 /* Remove UDP port filter */
352 wsm_set_udp_port_filter(priv
, &cw1200_udp_port_filter_off
);
354 /* Remove ethernet frame type filter */
355 wsm_set_ether_type_filter(priv
, &cw1200_ether_type_filter_off
);
357 /* Unlock datapath */
360 /* Unlock configuration mutex */
361 mutex_unlock(&priv
->conf_mutex
);