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 setup_timer(&pm
->stay_awake
, cw1200_pm_stay_awake_tmo
,
110 void cw1200_pm_deinit(struct cw1200_pm_state
*pm
)
112 del_timer_sync(&pm
->stay_awake
);
115 void cw1200_pm_stay_awake(struct cw1200_pm_state
*pm
,
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
);
126 static long cw1200_suspend_work(struct delayed_work
*work
)
128 int ret
= cancel_delayed_work(work
);
131 /* Timer is pending */
132 tmo
= work
->timer
.expires
- jiffies
;
141 static int cw1200_resume_work(struct cw1200_common
*priv
,
142 struct delayed_work
*work
,
148 return queue_delayed_work(priv
->workqueue
, work
, tmo
);
151 int cw1200_can_suspend(struct cw1200_common
*priv
)
153 if (atomic_read(&priv
->bh_rx
)) {
154 wiphy_dbg(priv
->hw
->wiphy
, "Suspend interrupted.\n");
159 EXPORT_SYMBOL_GPL(cw1200_can_suspend
);
161 int cw1200_wow_suspend(struct ieee80211_hw
*hw
, struct cfg80211_wowlan
*wowlan
)
163 struct cw1200_common
*priv
= hw
->priv
;
164 struct cw1200_pm_state
*pm_state
= &priv
->pm_state
;
165 struct cw1200_suspend_state
*state
;
168 spin_lock_bh(&pm_state
->lock
);
169 ret
= timer_pending(&pm_state
->stay_awake
);
170 spin_unlock_bh(&pm_state
->lock
);
174 /* Do not suspend when datapath is not idle */
175 if (priv
->tx_queue_stats
.num_queued
)
178 /* Make sure there is no configuration requests in progress. */
179 if (!mutex_trylock(&priv
->conf_mutex
))
182 /* Ensure pending operations are done.
183 * Note also that wow_suspend must return in ~2.5sec, before
184 * watchdog is triggered.
186 if (priv
->channel_switch_in_progress
)
189 /* Do not suspend when join is pending */
190 if (priv
->join_pending
)
193 /* Do not suspend when scanning */
194 if (down_trylock(&priv
->scan
.lock
))
198 wsm_lock_tx_async(priv
);
200 /* Wait to avoid possible race with bh code.
201 * But do not wait too long...
203 if (wait_event_timeout(priv
->bh_evt_wq
,
204 !priv
->hw_bufs_used
, HZ
/ 10) <= 0)
208 wsm_set_udp_port_filter(priv
, &cw1200_udp_port_filter_on
.hdr
);
210 /* Set ethernet frame type filter */
211 wsm_set_ether_type_filter(priv
, &cw1200_ether_type_filter_on
.hdr
);
214 state
= kzalloc(sizeof(struct cw1200_suspend_state
), GFP_KERNEL
);
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) {
231 /* Store delayed work states. */
232 state
->bss_loss_tmo
=
233 cw1200_suspend_work(&priv
->bss_loss_work
);
235 cw1200_suspend_work(&priv
->join_timeout
);
236 state
->direct_probe
=
237 cw1200_suspend_work(&priv
->scan
.probe_work
);
239 cw1200_suspend_work(&priv
->link_id_gc_work
);
241 cancel_delayed_work_sync(&priv
->clear_recent_scan_work
);
242 atomic_set(&priv
->recent_scan
, 0);
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
);
254 /* Stop serving thread */
255 if (cw1200_bh_suspend(priv
))
258 ret
= timer_pending(&priv
->mcast_timeout
);
262 /* Store suspend state */
263 pm_state
->suspend_state
= state
;
265 /* Enable IRQ wake */
266 ret
= priv
->hwbus_ops
->power_mgmt(priv
->hwbus_priv
, true);
268 wiphy_err(priv
->hw
->wiphy
,
269 "PM request failed: %d. WoW is disabled.\n", ret
);
270 cw1200_wow_resume(hw
);
274 /* Force resume if event is coming from the device. */
275 if (atomic_read(&priv
->bh_rx
)) {
276 cw1200_wow_resume(hw
);
283 WARN_ON(cw1200_bh_resume(priv
));
285 cw1200_resume_work(priv
, &priv
->bss_loss_work
,
286 state
->bss_loss_tmo
);
287 cw1200_resume_work(priv
, &priv
->join_timeout
,
289 cw1200_resume_work(priv
, &priv
->scan
.probe_work
,
290 state
->direct_probe
);
291 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
);