xref: /openbmc/linux/drivers/net/wireless/st/cw1200/pm.c (revision 2a598d0b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Mac80211 power management API for ST-Ericsson CW1200 drivers
4  *
5  * Copyright (c) 2011, ST-Ericsson
6  * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
7  */
8 
9 #include <linux/module.h>
10 #include <linux/if_ether.h>
11 #include "cw1200.h"
12 #include "pm.h"
13 #include "sta.h"
14 #include "bh.h"
15 #include "hwbus.h"
16 
17 #define CW1200_BEACON_SKIPPING_MULTIPLIER 3
18 
19 struct cw1200_udp_port_filter {
20 	struct wsm_udp_port_filter_hdr hdr;
21 	/* Up to 4 filters are allowed. */
22 	struct wsm_udp_port_filter filters[WSM_MAX_FILTER_ELEMENTS];
23 } __packed;
24 
25 struct cw1200_ether_type_filter {
26 	struct wsm_ether_type_filter_hdr hdr;
27 	/* Up to 4 filters are allowed. */
28 	struct wsm_ether_type_filter filters[WSM_MAX_FILTER_ELEMENTS];
29 } __packed;
30 
31 static struct cw1200_udp_port_filter cw1200_udp_port_filter_on = {
32 	.hdr.num = 2,
33 	.filters = {
34 		[0] = {
35 			.action = WSM_FILTER_ACTION_FILTER_OUT,
36 			.type = WSM_FILTER_PORT_TYPE_DST,
37 			.port = __cpu_to_le16(67), /* DHCP Bootps */
38 		},
39 		[1] = {
40 			.action = WSM_FILTER_ACTION_FILTER_OUT,
41 			.type = WSM_FILTER_PORT_TYPE_DST,
42 			.port = __cpu_to_le16(68), /* DHCP Bootpc */
43 		},
44 	}
45 };
46 
47 static struct wsm_udp_port_filter_hdr cw1200_udp_port_filter_off = {
48 	.num = 0,
49 };
50 
51 #ifndef ETH_P_WAPI
52 #define ETH_P_WAPI     0x88B4
53 #endif
54 
55 static struct cw1200_ether_type_filter cw1200_ether_type_filter_on = {
56 	.hdr.num = 4,
57 	.filters = {
58 		[0] = {
59 			.action = WSM_FILTER_ACTION_FILTER_IN,
60 			.type = __cpu_to_le16(ETH_P_IP),
61 		},
62 		[1] = {
63 			.action = WSM_FILTER_ACTION_FILTER_IN,
64 			.type = __cpu_to_le16(ETH_P_PAE),
65 		},
66 		[2] = {
67 			.action = WSM_FILTER_ACTION_FILTER_IN,
68 			.type = __cpu_to_le16(ETH_P_WAPI),
69 		},
70 		[3] = {
71 			.action = WSM_FILTER_ACTION_FILTER_IN,
72 			.type = __cpu_to_le16(ETH_P_ARP),
73 		},
74 	},
75 };
76 
77 static struct wsm_ether_type_filter_hdr cw1200_ether_type_filter_off = {
78 	.num = 0,
79 };
80 
81 /* private */
82 struct cw1200_suspend_state {
83 	unsigned long bss_loss_tmo;
84 	unsigned long join_tmo;
85 	unsigned long direct_probe;
86 	unsigned long link_id_gc;
87 	bool beacon_skipping;
88 	u8 prev_ps_mode;
89 };
90 
91 static void cw1200_pm_stay_awake_tmo(struct timer_list *unused)
92 {
93 	/* XXX what's the point of this ? */
94 }
95 
96 int cw1200_pm_init(struct cw1200_pm_state *pm,
97 		   struct cw1200_common *priv)
98 {
99 	spin_lock_init(&pm->lock);
100 
101 	timer_setup(&pm->stay_awake, cw1200_pm_stay_awake_tmo, 0);
102 
103 	return 0;
104 }
105 
106 void cw1200_pm_deinit(struct cw1200_pm_state *pm)
107 {
108 	del_timer_sync(&pm->stay_awake);
109 }
110 
111 void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
112 			  unsigned long tmo)
113 {
114 	long cur_tmo;
115 	spin_lock_bh(&pm->lock);
116 	cur_tmo = pm->stay_awake.expires - jiffies;
117 	if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo)
118 		mod_timer(&pm->stay_awake, jiffies + tmo);
119 	spin_unlock_bh(&pm->lock);
120 }
121 
122 static long cw1200_suspend_work(struct delayed_work *work)
123 {
124 	int ret = cancel_delayed_work(work);
125 	long tmo;
126 	if (ret > 0) {
127 		/* Timer is pending */
128 		tmo = work->timer.expires - jiffies;
129 		if (tmo < 0)
130 			tmo = 0;
131 	} else {
132 		tmo = -1;
133 	}
134 	return tmo;
135 }
136 
137 static int cw1200_resume_work(struct cw1200_common *priv,
138 			       struct delayed_work *work,
139 			       unsigned long tmo)
140 {
141 	if ((long)tmo < 0)
142 		return 1;
143 
144 	return queue_delayed_work(priv->workqueue, work, tmo);
145 }
146 
147 int cw1200_can_suspend(struct cw1200_common *priv)
148 {
149 	if (atomic_read(&priv->bh_rx)) {
150 		wiphy_dbg(priv->hw->wiphy, "Suspend interrupted.\n");
151 		return 0;
152 	}
153 	return 1;
154 }
155 EXPORT_SYMBOL_GPL(cw1200_can_suspend);
156 
157 int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
158 {
159 	struct cw1200_common *priv = hw->priv;
160 	struct cw1200_pm_state *pm_state = &priv->pm_state;
161 	struct cw1200_suspend_state *state;
162 	int ret;
163 
164 	spin_lock_bh(&pm_state->lock);
165 	ret = timer_pending(&pm_state->stay_awake);
166 	spin_unlock_bh(&pm_state->lock);
167 	if (ret)
168 		return -EAGAIN;
169 
170 	/* Do not suspend when datapath is not idle */
171 	if (priv->tx_queue_stats.num_queued)
172 		return -EBUSY;
173 
174 	/* Make sure there is no configuration requests in progress. */
175 	if (!mutex_trylock(&priv->conf_mutex))
176 		return -EBUSY;
177 
178 	/* Ensure pending operations are done.
179 	 * Note also that wow_suspend must return in ~2.5sec, before
180 	 * watchdog is triggered.
181 	 */
182 	if (priv->channel_switch_in_progress)
183 		goto revert1;
184 
185 	/* Do not suspend when join is pending */
186 	if (priv->join_pending)
187 		goto revert1;
188 
189 	/* Do not suspend when scanning */
190 	if (down_trylock(&priv->scan.lock))
191 		goto revert1;
192 
193 	/* Lock TX. */
194 	wsm_lock_tx_async(priv);
195 
196 	/* Wait to avoid possible race with bh code.
197 	 * But do not wait too long...
198 	 */
199 	if (wait_event_timeout(priv->bh_evt_wq,
200 			       !priv->hw_bufs_used, HZ / 10) <= 0)
201 		goto revert2;
202 
203 	/* Set UDP filter */
204 	wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_on.hdr);
205 
206 	/* Set ethernet frame type filter */
207 	wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_on.hdr);
208 
209 	/* Allocate state */
210 	state = kzalloc(sizeof(struct cw1200_suspend_state), GFP_KERNEL);
211 	if (!state)
212 		goto revert3;
213 
214 	/* Change to legacy PS while going to suspend */
215 	if (!priv->vif->p2p &&
216 	    priv->join_status == CW1200_JOIN_STATUS_STA &&
217 	    priv->powersave_mode.mode != WSM_PSM_PS) {
218 		state->prev_ps_mode = priv->powersave_mode.mode;
219 		priv->powersave_mode.mode = WSM_PSM_PS;
220 		cw1200_set_pm(priv, &priv->powersave_mode);
221 		if (wait_event_interruptible_timeout(priv->ps_mode_switch_done,
222 						     !priv->ps_mode_switch_in_progress, 1*HZ) <= 0) {
223 			goto revert4;
224 		}
225 	}
226 
227 	/* Store delayed work states. */
228 	state->bss_loss_tmo =
229 		cw1200_suspend_work(&priv->bss_loss_work);
230 	state->join_tmo =
231 		cw1200_suspend_work(&priv->join_timeout);
232 	state->direct_probe =
233 		cw1200_suspend_work(&priv->scan.probe_work);
234 	state->link_id_gc =
235 		cw1200_suspend_work(&priv->link_id_gc_work);
236 
237 	cancel_delayed_work_sync(&priv->clear_recent_scan_work);
238 	atomic_set(&priv->recent_scan, 0);
239 
240 	/* Enable beacon skipping */
241 	if (priv->join_status == CW1200_JOIN_STATUS_STA &&
242 	    priv->join_dtim_period &&
243 	    !priv->has_multicast_subscription) {
244 		state->beacon_skipping = true;
245 		wsm_set_beacon_wakeup_period(priv,
246 					     priv->join_dtim_period,
247 					     CW1200_BEACON_SKIPPING_MULTIPLIER * priv->join_dtim_period);
248 	}
249 
250 	/* Stop serving thread */
251 	if (cw1200_bh_suspend(priv))
252 		goto revert5;
253 
254 	ret = timer_pending(&priv->mcast_timeout);
255 	if (ret)
256 		goto revert6;
257 
258 	/* Store suspend state */
259 	pm_state->suspend_state = state;
260 
261 	/* Enable IRQ wake */
262 	ret = priv->hwbus_ops->power_mgmt(priv->hwbus_priv, true);
263 	if (ret) {
264 		wiphy_err(priv->hw->wiphy,
265 			  "PM request failed: %d. WoW is disabled.\n", ret);
266 		cw1200_wow_resume(hw);
267 		return -EBUSY;
268 	}
269 
270 	/* Force resume if event is coming from the device. */
271 	if (atomic_read(&priv->bh_rx)) {
272 		cw1200_wow_resume(hw);
273 		return -EAGAIN;
274 	}
275 
276 	return 0;
277 
278 revert6:
279 	WARN_ON(cw1200_bh_resume(priv));
280 revert5:
281 	cw1200_resume_work(priv, &priv->bss_loss_work,
282 			   state->bss_loss_tmo);
283 	cw1200_resume_work(priv, &priv->join_timeout,
284 			   state->join_tmo);
285 	cw1200_resume_work(priv, &priv->scan.probe_work,
286 			   state->direct_probe);
287 	cw1200_resume_work(priv, &priv->link_id_gc_work,
288 			   state->link_id_gc);
289 revert4:
290 	kfree(state);
291 revert3:
292 	wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off);
293 	wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off);
294 revert2:
295 	wsm_unlock_tx(priv);
296 	up(&priv->scan.lock);
297 revert1:
298 	mutex_unlock(&priv->conf_mutex);
299 	return -EBUSY;
300 }
301 
302 int cw1200_wow_resume(struct ieee80211_hw *hw)
303 {
304 	struct cw1200_common *priv = hw->priv;
305 	struct cw1200_pm_state *pm_state = &priv->pm_state;
306 	struct cw1200_suspend_state *state;
307 
308 	state = pm_state->suspend_state;
309 	pm_state->suspend_state = NULL;
310 
311 	/* Disable IRQ wake */
312 	priv->hwbus_ops->power_mgmt(priv->hwbus_priv, false);
313 
314 	/* Scan.lock must be released before BH is resumed other way
315 	 * in case when BSS_LOST command arrived the processing of the
316 	 * command will be delayed.
317 	 */
318 	up(&priv->scan.lock);
319 
320 	/* Resume BH thread */
321 	WARN_ON(cw1200_bh_resume(priv));
322 
323 	/* Restores previous PS mode */
324 	if (!priv->vif->p2p && priv->join_status == CW1200_JOIN_STATUS_STA) {
325 		priv->powersave_mode.mode = state->prev_ps_mode;
326 		cw1200_set_pm(priv, &priv->powersave_mode);
327 	}
328 
329 	if (state->beacon_skipping) {
330 		wsm_set_beacon_wakeup_period(priv, priv->beacon_int *
331 					     priv->join_dtim_period >
332 					     MAX_BEACON_SKIP_TIME_MS ? 1 :
333 					     priv->join_dtim_period, 0);
334 		state->beacon_skipping = false;
335 	}
336 
337 	/* Resume delayed work */
338 	cw1200_resume_work(priv, &priv->bss_loss_work,
339 			   state->bss_loss_tmo);
340 	cw1200_resume_work(priv, &priv->join_timeout,
341 			   state->join_tmo);
342 	cw1200_resume_work(priv, &priv->scan.probe_work,
343 			   state->direct_probe);
344 	cw1200_resume_work(priv, &priv->link_id_gc_work,
345 			   state->link_id_gc);
346 
347 	/* Remove UDP port filter */
348 	wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off);
349 
350 	/* Remove ethernet frame type filter */
351 	wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off);
352 
353 	/* Unlock datapath */
354 	wsm_unlock_tx(priv);
355 
356 	/* Unlock configuration mutex */
357 	mutex_unlock(&priv->conf_mutex);
358 
359 	/* Free memory */
360 	kfree(state);
361 
362 	return 0;
363 }
364