• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
cw1200_pm_stay_awake_tmo(unsigned long arg)94 static void cw1200_pm_stay_awake_tmo(unsigned long arg)
95 {
96 	/* XXX what's the point of this ? */
97 }
98 
cw1200_pm_init(struct cw1200_pm_state * pm,struct cw1200_common * priv)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 
cw1200_pm_deinit(struct cw1200_pm_state * pm)111 void cw1200_pm_deinit(struct cw1200_pm_state *pm)
112 {
113 	del_timer_sync(&pm->stay_awake);
114 }
115 
cw1200_pm_stay_awake(struct cw1200_pm_state * pm,unsigned long tmo)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 
cw1200_suspend_work(struct delayed_work * work)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 
cw1200_resume_work(struct cw1200_common * priv,struct delayed_work * work,unsigned long tmo)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 
cw1200_can_suspend(struct cw1200_common * priv)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 
cw1200_wow_suspend(struct ieee80211_hw * hw,struct cfg80211_wowlan * wowlan)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 
cw1200_wow_resume(struct ieee80211_hw * hw)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 }
369