1 /*
2 * PM implementation for XRadio drivers
3 *
4 * Copyright (c) 2013
5 * Xradio Technology Co., Ltd. <www.xradiotech.com>
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/platform_device.h>
13 #include <linux/if_ether.h>
14 #include "xradio.h"
15 #include "pm.h"
16 #include "sta.h"
17 #include "bh.h"
18 #include "sbus.h"
19 #include "platform.h"
20 #ifdef CONFIG_XRADIO_EXTEND_SUSPEND
21 #include <linux/power/scenelock.h>
22 #endif
23
24 #ifdef CONFIG_XRADIO_NOMAL_SUSPEND_FORCE
25 #include <linux/power/scenelock.h>
26 struct scene_lock wifi_lock;
27 #endif
28
29 #define XRADIO_BEACON_SKIPPING_MULTIPLIER 3
30
31 struct xradio_udp_port_filter {
32 struct wsm_udp_port_filter_hdr hdr;
33 struct wsm_udp_port_filter dhcp;
34 struct wsm_udp_port_filter upnp;
35 } __packed;
36
37 struct xradio_ether_type_filter {
38 struct wsm_ether_type_filter_hdr hdr;
39 struct wsm_ether_type_filter ip;
40 struct wsm_ether_type_filter pae;
41 struct wsm_ether_type_filter wapi;
42 } __packed;
43
44 static struct xradio_udp_port_filter xradio_udp_port_filter_on = {
45 .hdr.nrFilters = 2,
46 .dhcp = {
47 .filterAction = WSM_FILTER_ACTION_FILTER_OUT,
48 .portType = WSM_FILTER_PORT_TYPE_DST,
49 .udpPort = __cpu_to_le16(67),
50 },
51 .upnp = {
52 .filterAction = WSM_FILTER_ACTION_FILTER_OUT,
53 .portType = WSM_FILTER_PORT_TYPE_DST,
54 .udpPort = __cpu_to_le16(1900),
55 },
56 /* Please add other known ports to be filtered out here and
57 * update nrFilters field in the header.
58 * Up to 4 filters are allowed. */
59 };
60
61 static struct wsm_udp_port_filter_hdr xradio_udp_port_filter_off = {
62 .nrFilters = 0,
63 };
64
65 #ifndef ETH_P_WAPI
66 #define ETH_P_WAPI 0x88B4
67 #endif
68
69 #ifdef TES_P2P_000B_DISABLE_EAPOL_FILTER
70 /* TES_P2P_000B WorkAround:
71 * when the link keep 10min more or less(i am not sure),
72 * wpa_s session maybe expired, and want to update group key.
73 * it will use eapol frame(802.1x, 0x888E).
74 * if driver suspend, and discard eapol frame, then session end.
75 * i don't know why original code discards eapol frame in suspend.
76 * but now make this filter disable as WorkAround.*/
77 static struct xradio_ether_type_filter xradio_ether_type_filter_on = {
78 .hdr.nrFilters = 1,
79 /* .ip = {
80 .filterAction = WSM_FILTER_ACTION_FILTER_IN,
81 .etherType = __cpu_to_le16(ETH_P_IP),
82 }, */
83 /* .pae = {
84 .filterAction = WSM_FILTER_ACTION_FILTER_IN,
85 .etherType = __cpu_to_le16(ETH_P_PAE),
86 }, */
87 .wapi = {
88 .filterAction = WSM_FILTER_ACTION_FILTER_IN,
89 .etherType = __cpu_to_le16(ETH_P_WAPI),
90 },
91 /* Please add other known ether types to be filtered out here and
92 * update nrFilters field in the header.
93 * Up to 4 filters are allowed. */
94 };
95 #else
96 static struct xradio_ether_type_filter xradio_ether_type_filter_on = {
97 .hdr.nrFilters = 2,
98 /* .ip = {
99 .filterAction = WSM_FILTER_ACTION_FILTER_IN,
100 .etherType = __cpu_to_le16(ETH_P_IP),
101 }, */
102 .pae = {
103 .filterAction = WSM_FILTER_ACTION_FILTER_IN,
104 .etherType = __cpu_to_le16(ETH_P_PAE),
105 },
106 .wapi = {
107 .filterAction = WSM_FILTER_ACTION_FILTER_IN,
108 .etherType = __cpu_to_le16(ETH_P_WAPI),
109 },
110 /* Please add other known ether types to be filtered out here and
111 * update nrFilters field in the header.
112 * Up to 4 filters are allowed. */
113 };
114 #endif
115
116 static struct wsm_ether_type_filter_hdr xradio_ether_type_filter_off = {
117 .nrFilters = 0,
118 };
119
120 static int xradio_suspend_late(struct device *dev);
121 static void xradio_pm_release(struct device *dev);
122 static int xradio_pm_probe(struct platform_device *pdev);
123 static int __xradio_wow_suspend(struct xradio_vif *priv,
124 struct cfg80211_wowlan *wowlan);
125 static int __xradio_wow_resume(struct xradio_vif *priv);
126 #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF
127 static int xradio_poweroff_suspend(struct xradio_common *hw_priv);
128 static int xradio_poweroff_resume(struct xradio_common *hw_priv);
129 #endif
130
131
132 /* private */
133 struct xradio_suspend_state {
134 unsigned long bss_loss_tmo;
135 unsigned long connection_loss_tmo;
136 unsigned long join_tmo;
137 unsigned long direct_probe;
138 unsigned long link_id_gc;
139 bool beacon_skipping;
140 };
141
142 static const struct dev_pm_ops xradio_pm_ops = {
143 .suspend_noirq = xradio_suspend_late,
144 };
145
146 static struct platform_driver xradio_power_driver = {
147 .probe = xradio_pm_probe,
148 .driver = {
149 .name = XRADIO_PLAT_DEVICE,
150 .pm = &xradio_pm_ops,
151 },
152 };
153
154 #ifdef CONFIG_XRADIO_DEBUG
155 struct timespec64 suspend_time;
156 struct timespec64 resume_time;
xradio_realtime_interval(struct timespec64 * oldtime,struct timespec64 * newtime)157 u32 xradio_realtime_interval(struct timespec64 *oldtime, struct timespec64 *newtime)
158 {
159 u32 time_int;
160 xr_do_gettimeofday(newtime);
161 time_int = (newtime->tv_sec - oldtime->tv_sec) * 1000 + \
162 (newtime->tv_nsec - oldtime->tv_nsec) / 1000000;
163 return time_int;
164 }
165 #endif
166
xradio_pm_init_common(struct xradio_pm_state * pm,struct xradio_common * hw_priv)167 static int xradio_pm_init_common(struct xradio_pm_state *pm,
168 struct xradio_common *hw_priv)
169 {
170 int ret;
171 pm_printk(XRADIO_DBG_TRC, "%s\n", __func__);
172 #ifdef CONFIG_XRADIO_DEBUG
173 xr_do_gettimeofday(&resume_time);
174 #endif
175
176 spin_lock_init(&pm->lock);
177 /* Register pm driver. */
178 ret = platform_driver_register(&xradio_power_driver);
179 if (ret) {
180 pm_printk(XRADIO_DBG_ERROR,
181 "%s:platform_driver_register failed(%d)!\n",
182 __func__, ret);
183 }
184
185 #ifdef CONFIG_XRADIO_NOMAL_SUSPEND_FORCE
186 scene_lock_init(&wifi_lock, SCENE_NORMAL_STANDBY, "wifinormal_standby");
187 scene_lock(&wifi_lock);
188 if (!check_scene_locked(SCENE_NORMAL_STANDBY))
189 pm_printk(XRADIO_DBG_NIY, "normal standby lock success!\n");
190 else
191 pm_printk(XRADIO_DBG_ERROR, "normal standby lock failed!\n");
192 #endif
193
194 return ret;
195 }
196
xradio_pm_deinit_common(struct xradio_pm_state * pm)197 static void xradio_pm_deinit_common(struct xradio_pm_state *pm)
198 {
199 pm_printk(XRADIO_DBG_TRC, "%s\n", __func__);
200 platform_driver_unregister(&xradio_power_driver);
201 #ifdef CONFIG_XRADIO_NOMAL_SUSPEND_FORCE
202 scene_unlock(&wifi_lock);
203 if (!check_scene_locked(SCENE_NORMAL_STANDBY))
204 pm_printk(XRADIO_DBG_ERROR, "normal standby unlock failed!\n");
205 else
206 pm_printk(XRADIO_DBG_NIY, "normal standby unlock success!\n");
207 #endif
208 }
209
210 #ifdef CONFIG_WAKELOCK
211
xradio_pm_init(struct xradio_pm_state * pm,struct xradio_common * hw_priv)212 int xradio_pm_init(struct xradio_pm_state *pm,
213 struct xradio_common *hw_priv)
214 {
215 int ret = 0;
216 pm_printk(XRADIO_DBG_TRC, "%s\n", __func__);
217
218 ret = xradio_pm_init_common(pm, hw_priv);
219 if (!ret)
220 wake_lock_init(&pm->wakelock, WAKE_LOCK_SUSPEND, XRADIO_WAKE_LOCK);
221 else
222 pm_printk(XRADIO_DBG_ERROR, "xradio_pm_init_common failed!\n");
223 return ret;
224 }
225
xradio_pm_deinit(struct xradio_pm_state * pm)226 void xradio_pm_deinit(struct xradio_pm_state *pm)
227 {
228 pm_printk(XRADIO_DBG_TRC, "%s\n", __func__);
229 if (wake_lock_active(&pm->wakelock))
230 wake_unlock(&pm->wakelock);
231 wake_lock_destroy(&pm->wakelock);
232 xradio_pm_deinit_common(pm);
233 }
234
xradio_pm_stay_awake(struct xradio_pm_state * pm,unsigned long tmo)235 void xradio_pm_stay_awake(struct xradio_pm_state *pm,
236 unsigned long tmo)
237 {
238 long cur_tmo;
239 pm_printk(XRADIO_DBG_MSG, "%s\n", __func__);
240
241 spin_lock_bh(&pm->lock);
242 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
243 cur_tmo = pm->wakelock.ws.timer.expires - jiffies;
244 #else
245 cur_tmo = pm->wakelock.expires - jiffies;
246 #endif
247 if (!wake_lock_active(&pm->wakelock) || cur_tmo < (long)tmo)
248 wake_lock_timeout(&pm->wakelock, tmo);
249 spin_unlock_bh(&pm->lock);
250 }
xradio_pm_lock_awake(struct xradio_pm_state * pm)251 void xradio_pm_lock_awake(struct xradio_pm_state *pm)
252 {
253 pm_printk(XRADIO_DBG_NIY, "%s\n", __func__);
254 spin_lock_bh(&pm->lock);
255 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
256 pm->expires_save = pm->wakelock.ws.timer.expires;
257 #else
258 pm->expires_save = pm->wakelock.expires;
259 #endif
260 if (!wake_lock_active(&pm->wakelock) ||
261 time_before((unsigned long)pm->expires_save, jiffies)) {
262 pm->expires_save = 0;
263 }
264 wake_lock(&pm->wakelock);
265 spin_unlock_bh(&pm->lock);
266 }
xradio_pm_unlock_awake(struct xradio_pm_state * pm)267 void xradio_pm_unlock_awake(struct xradio_pm_state *pm)
268 {
269 pm_printk(XRADIO_DBG_NIY, "%s\n", __func__);
270 spin_lock_bh(&pm->lock);
271 if (wake_lock_active(&pm->wakelock)) {
272 wake_unlock(&pm->wakelock);
273 if (pm->expires_save &&
274 time_before(jiffies, (unsigned long)pm->expires_save)) {
275 pm->expires_save -= jiffies;
276 wake_lock_timeout(&pm->wakelock, pm->expires_save);
277 }
278 }
279 pm->expires_save = 0;
280 spin_unlock_bh(&pm->lock);
281 }
282
283 #else /* CONFIG_WAKELOCK */
284
xradio_pm_stay_awake_tmo(struct timer_list * t)285 static void xradio_pm_stay_awake_tmo(struct timer_list *t)
286 {
287 struct xradio_pm_state *pm = from_timer(pm, t, stay_awake);
288
289 atomic_set(&pm->status, XRADIO_PM_STATE_ALLOW_SUSPEND);
290 }
291
xradio_pm_init(struct xradio_pm_state * pm,struct xradio_common * hw_priv)292 int xradio_pm_init(struct xradio_pm_state *pm,
293 struct xradio_common *hw_priv)
294 {
295 int ret = 0;
296 pm_printk(XRADIO_DBG_MSG, "%s\n", __func__);
297
298 ret = xradio_pm_init_common(pm, hw_priv);
299 if (!ret) {
300 timer_setup(&pm->stay_awake, xradio_pm_stay_awake_tmo, 0);
301 atomic_set(&pm->status, XRADIO_PM_STATE_ALLOW_SUSPEND);
302 } else
303 pm_printk(XRADIO_DBG_ERROR, "xradio_pm_init_common failed!\n");
304 return ret;
305 }
306
xradio_pm_deinit(struct xradio_pm_state * pm)307 void xradio_pm_deinit(struct xradio_pm_state *pm)
308 {
309 pm_printk(XRADIO_DBG_TRC, "%s\n", __func__);
310 del_timer_sync(&pm->stay_awake);
311 xradio_pm_deinit_common(pm);
312 }
313
xradio_pm_stay_awake(struct xradio_pm_state * pm,unsigned long tmo)314 void xradio_pm_stay_awake(struct xradio_pm_state *pm,
315 unsigned long tmo)
316 {
317 long cur_tmo;
318 pm_printk(XRADIO_DBG_MSG, "%s\n", __func__);
319
320 spin_lock_bh(&pm->lock);
321 atomic_set(&pm->status, XRADIO_PM_STATE_KEEP_WAKE);
322 cur_tmo = pm->stay_awake.expires - jiffies;
323 if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo)
324 mod_timer(&pm->stay_awake, jiffies + tmo);
325 spin_unlock_bh(&pm->lock);
326 }
xradio_pm_lock_awake(struct xradio_pm_state * pm)327 void xradio_pm_lock_awake(struct xradio_pm_state *pm)
328 {
329 pm_printk(XRADIO_DBG_NIY, "%s\n", __func__);
330 spin_lock_bh(&pm->lock);
331 if (timer_pending(&pm->stay_awake))
332 pm->expires_save = pm->stay_awake.expires;
333 else
334 pm->expires_save = jiffies;
335 mod_timer(&pm->stay_awake, jiffies + LONG_MAX);
336 spin_unlock_bh(&pm->lock);
337 }
xradio_pm_unlock_awake(struct xradio_pm_state * pm)338 void xradio_pm_unlock_awake(struct xradio_pm_state *pm)
339 {
340 pm_printk(XRADIO_DBG_NIY, "%s\n", __func__);
341 spin_lock_bh(&pm->lock);
342 if (time_before(jiffies, (unsigned long)pm->expires_save))
343 mod_timer(&pm->stay_awake, pm->expires_save);
344 else
345 mod_timer(&pm->stay_awake, jiffies + 5);
346 spin_unlock_bh(&pm->lock);
347 }
348 #endif /* CONFIG_WAKELOCK */
349
xradio_suspend_work(struct delayed_work * work)350 static long xradio_suspend_work(struct delayed_work *work)
351 {
352 int ret = cancel_delayed_work(work);
353 long tmo;
354 pm_printk(XRADIO_DBG_TRC, "%s\n", __func__);
355
356 if (ret > 0) {
357 /* Timer is pending */
358 tmo = work->timer.expires - jiffies;
359 if (tmo < 0)
360 tmo = 0;
361 } else {
362 tmo = -1;
363 }
364 return tmo;
365 }
366
xradio_resume_work(struct xradio_common * hw_priv,struct delayed_work * work,unsigned long tmo)367 static int xradio_resume_work(struct xradio_common *hw_priv,
368 struct delayed_work *work,
369 unsigned long tmo)
370 {
371 pm_printk(XRADIO_DBG_TRC, "%s\n", __func__);
372 if ((long)tmo < 0)
373 return 1;
374
375 return queue_delayed_work(hw_priv->workqueue, work, tmo);
376 }
377
xradio_suspend_late(struct device * dev)378 static int xradio_suspend_late(struct device *dev)
379 {
380 struct xradio_common *hw_priv = dev->platform_data;
381 pm_printk(XRADIO_DBG_NIY, "%s\n", __func__);
382 #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF
383 if (XRADIO_POWEROFF_SUSP == atomic_read(&hw_priv->suspend_state)) {
384 return 0; /* we don't rx data when power down wifi.*/
385 }
386 #endif
387
388 if (atomic_read(&hw_priv->bh_rx)) {
389 pm_printk(XRADIO_DBG_WARN, "%s: Suspend interrupted.\n", __func__);
390 return -EAGAIN;
391 }
392 return 0;
393 }
394
xradio_pm_release(struct device * dev)395 static void xradio_pm_release(struct device *dev)
396 {
397 pm_printk(XRADIO_DBG_TRC, "%s\n", __func__);
398 }
399
xradio_pm_probe(struct platform_device * pdev)400 static int xradio_pm_probe(struct platform_device *pdev)
401 {
402 pm_printk(XRADIO_DBG_TRC, "%s\n", __func__);
403 pdev->dev.release = xradio_pm_release;
404 return 0;
405 }
406
xradio_wow_suspend(struct ieee80211_hw * hw,struct cfg80211_wowlan * wowlan)407 int xradio_wow_suspend(struct ieee80211_hw *hw,
408 struct cfg80211_wowlan *wowlan)
409 {
410 struct xradio_common *hw_priv = hw->priv;
411 struct xradio_vif *priv;
412 int i, ret = 0;
413 int suspend_lock_state;
414 pm_printk(XRADIO_DBG_NIY, "%s, Activetime=%dms\n", __func__,
415 xradio_realtime_interval(&resume_time, &suspend_time));
416
417 if (hw_priv->bh_error) {
418 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
419 "because of bh_error occurs.\n");
420 return -EBUSY;
421 }
422 if (!atomic_read(&hw_priv->num_vifs))
423 pm_printk(XRADIO_DBG_WARN, "%s num_vifs=0\n", __func__);
424
425 #ifdef HW_RESTART
426 if (hw_priv->hw_restart == true) {
427 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
428 "because of hw_restart is working.\n");
429 return -EBUSY;
430 }
431
432 if (work_pending(&hw_priv->hw_restart_work)) {
433 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
434 "because of hw_restart_work prepare to worked.\n");
435 return -EBUSY;
436 }
437
438 if (hw_priv->hw_restart_work_running == true) {
439 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
440 "because of hw_restart_work is working.\n");
441 return -EBUSY;
442 }
443 #endif
444
445 #ifndef CONFIG_WAKELOCK
446 if (atomic_read(&hw_priv->pm_state.status) == XRADIO_PM_STATE_KEEP_WAKE) {
447 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
448 "because of pm_state need keep awake.\n");
449 return -EBUSY;
450 }
451 #endif
452
453 if (work_pending(&hw_priv->query_work)) {
454 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
455 "because of query_work is working.\n");
456 return -EBUSY;
457 }
458
459 #ifdef ROAM_OFFLOAD
460 xradio_for_each_vif(hw_priv, priv, i) {
461 #ifdef P2P_MULTIVIF
462 if ((i == (XRWL_MAX_VIFS - 1)) || !priv)
463 #else
464 if (!priv)
465 #endif
466 continue;
467 if ((priv->vif->type == NL80211_IFTYPE_STATION)
468 && (priv->join_status == XRADIO_JOIN_STATUS_STA)) {
469 down(&hw_priv->scan.lock);
470 hw_priv->scan.if_id = priv->if_id;
471 xradio_sched_scan_work(&hw_priv->scan.swork);
472 }
473 }
474 #endif /*ROAM_OFFLOAD*/
475
476 /* Do not suspend when datapath is not idle */
477 if (hw_priv->tx_queue_stats.num_queued[0] +
478 hw_priv->tx_queue_stats.num_queued[1]) {
479 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
480 "because of tx_queue is not empty.\n");
481 return -EBUSY;
482 }
483
484 #ifdef BH_PROC_THREAD
485 if (atomic_read(&hw_priv->proc.rx_queued) +
486 atomic_read(&hw_priv->proc.tx_queued)) {
487 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
488 "because of proc_queue is not empty.\n");
489 return -EBUSY;
490 }
491 #endif
492 suspend_lock_state = atomic_cmpxchg(&hw_priv->suspend_lock_state,
493 XRADIO_SUSPEND_LOCK_IDEL, XRADIO_SUSPEND_LOCK_SUSPEND);
494 if (suspend_lock_state == XRADIO_SUSPEND_LOCK_OTHERS) {
495 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
496 "because others are waiting for lock.\n");
497 goto revertm1;
498 }
499
500 /* Make sure there is no configuration requests in progress. */
501 if (down_trylock(&hw_priv->conf_lock)) {
502 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
503 "because of configuration requests.\n");
504 goto revertm1;
505 }
506
507 /* Make sure there is no wsm_oper_lock in progress. */
508 if (down_trylock(&hw_priv->wsm_oper_lock)) {
509 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
510 "because of wsm_oper_lock.\n");
511 goto revert0;
512 }
513
514 /* Do not suspend when scanning or ROC*/
515 if (down_trylock(&hw_priv->scan.lock)) {
516 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
517 "because of scan requests.\n");
518 goto revert1;
519 }
520
521 if (delayed_work_pending(&hw_priv->scan.probe_work)) {
522 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
523 "because of probe frames tx in progress.\n");
524 goto revert2;
525 }
526
527 /* Lock TX. */
528 wsm_lock_tx_async(hw_priv);
529
530 /* Wait to avoid possible race with bh code.
531 * But do not wait too long... */
532 if (wait_event_timeout(hw_priv->bh_evt_wq,
533 !hw_priv->hw_bufs_used, HZ / 10) <= 0) {
534 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
535 "because of there are frames not confirm.\n");
536 goto revert3;
537 }
538
539 #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF
540 #ifdef CONFIG_XRADIO_EXTEND_SUSPEND
541 if (check_scene_locked(SCENE_SUPER_STANDBY) == 0) {
542 if (xradio_poweroff_suspend(hw_priv)) {
543 pm_printk(XRADIO_DBG_WARN, "Don't suspend " \
544 "because of xradio_poweroff_suspend failed.\n");
545 goto revert3;
546 }
547 return 0;
548 }
549
550 #else
551 if (xradio_poweroff_suspend(hw_priv)) {
552 pm_printk(XRADIO_DBG_WARN, "Don't suspend " \
553 "because of xradio_poweroff_suspend failed.\n");
554 goto revert3;
555 }
556 return 0;
557
558 #endif
559 #endif
560
561 xradio_for_each_vif(hw_priv, priv, i) {
562 #ifdef P2P_MULTIVIF
563 if ((i == (XRWL_MAX_VIFS - 1)) || !priv)
564 #else
565 if (!priv)
566 #endif
567 continue;
568
569 ret = __xradio_wow_suspend(priv, wowlan);
570 if (ret) {
571 for (; i >= 0; i--) {
572 if (!hw_priv->vif_list[i])
573 continue;
574 priv = (struct xradio_vif *)hw_priv->vif_list[i]->drv_priv;
575 __xradio_wow_resume(priv);
576 }
577 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
578 "because of __xradio_wow_suspend failed!\n");
579 goto revert3;
580 }
581 }
582
583 /* Stop serving thread */
584 if (xradio_bh_suspend(hw_priv)) {
585 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
586 "because of xradio_bh_suspend failed!\n");
587 goto revert4;
588 }
589
590 /* Enable IRQ wake */
591 ret = hw_priv->sbus_ops->power_mgmt(hw_priv->sbus_priv, true);
592 if (ret) {
593 pm_printk(XRADIO_DBG_WARN, "Don't suspend sbus pm failed\n");
594 goto revert5;
595 }
596
597 /* Force resume if event is coming from the device. */
598 if (atomic_read(&hw_priv->bh_rx)) {
599 pm_printk(XRADIO_DBG_WARN, "Don't suspend "
600 "because of recieved rx event!\n");
601 goto revert6;
602 }
603 atomic_set(&hw_priv->suspend_state, XRADIO_CONNECT_SUSP);
604 return 0;
605
606 revert6:
607 hw_priv->sbus_ops->power_mgmt(hw_priv->sbus_priv, false);
608 revert5:
609 xradio_bh_resume(hw_priv);
610 revert4:
611 xradio_for_each_vif(hw_priv, priv, i) {
612 #ifdef P2P_MULTIVIF
613 if ((i == (XRWL_MAX_VIFS - 1)) || !priv)
614 #else
615 if (!priv)
616 #endif
617 continue;
618 ret = __xradio_wow_resume(priv);
619 if (ret) {
620 pm_printk(XRADIO_DBG_ERROR,
621 "%s:__xradio_wow_resume failed!\n", __func__);
622 break;
623 }
624 }
625 revert3:
626 wsm_unlock_tx(hw_priv);
627 revert2:
628 up(&hw_priv->scan.lock);
629 revert1:
630 up(&hw_priv->wsm_oper_lock);
631 revert0:
632 up(&hw_priv->conf_lock);
633 revertm1:
634 return -EBUSY;
635 }
636
__xradio_wow_suspend(struct xradio_vif * priv,struct cfg80211_wowlan * wowlan)637 static int __xradio_wow_suspend(struct xradio_vif *priv,
638 struct cfg80211_wowlan *wowlan)
639 {
640 struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv);
641 struct xradio_pm_state_vif *pm_state_vif = &priv->pm_state_vif;
642 struct xradio_suspend_state *state;
643 int ret;
644 #ifdef MCAST_FWDING
645 struct wsm_forwarding_offload fwdoffload = {
646 .fwenable = 0x1,
647 .flags = 0x1,
648 };
649 #endif
650 pm_printk(XRADIO_DBG_NIY, "%s\n", __func__);
651
652 /* Do not suspend when join work is scheduled */
653 if (work_pending(&priv->join_work)) {
654 pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend "
655 "when join work is scheduled\n", __func__);
656 goto revert1;
657 }
658
659 /* Set UDP filter */
660 wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_on.hdr,
661 priv->if_id);
662
663 /* Set ethernet frame type filter */
664 wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_on.hdr,
665 priv->if_id);
666
667 /* Set IP multicast filter */
668 wsm_set_host_sleep(hw_priv, 1, priv->if_id);
669
670 if (priv->join_status == XRADIO_JOIN_STATUS_AP)
671 WARN_ON(wsm_set_keepalive_filter(priv, true));
672
673 #ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE
674 /* Set Multicast Address Filter */
675 if (priv->multicast_filter.numOfAddresses) {
676 priv->multicast_filter.enable = 1;
677 wsm_set_multicast_filter(hw_priv, &priv->multicast_filter,
678 priv->if_id);
679 }
680
681 /* Set Enable Broadcast Address Filter */
682 priv->broadcast_filter.action_mode = 1;
683 if (priv->join_status == XRADIO_JOIN_STATUS_AP)
684 priv->broadcast_filter.address_mode = 3;
685
686 xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter);
687 #endif
688
689 #ifdef MCAST_FWDING
690 if (priv->join_status == XRADIO_JOIN_STATUS_AP)
691 WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload, priv->if_id));
692 #endif
693
694 /* Allocate state */
695 state = xr_kzalloc(sizeof(struct xradio_suspend_state), false);
696 if (!state) {
697 pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend "
698 "alloc xradio_suspend_state failed.\n", __func__);
699 goto revert2;
700 }
701 /* Store delayed work states. */
702 state->bss_loss_tmo = xradio_suspend_work(&priv->bss_loss_work);
703 state->connection_loss_tmo = xradio_suspend_work(&priv->connection_loss_work);
704 state->join_tmo = xradio_suspend_work(&priv->join_timeout);
705 state->link_id_gc = xradio_suspend_work(&priv->link_id_gc_work);
706
707 #ifndef XRADIO_USE_LONG_DTIM_PERIOD
708 /* Enable beacon skipping */
709 if (priv->join_status == XRADIO_JOIN_STATUS_STA &&
710 priv->join_dtim_period < 3) {
711 /* priv->join_dtim_period && !priv->has_multicast_subscription) { */
712 state->beacon_skipping = true;
713 wsm_set_beacon_wakeup_period(hw_priv,
714 priv->join_dtim_period * XRADIO_BEACON_SKIPPING_MULTIPLIER,
715 0, priv->if_id);
716 pm_printk(XRADIO_DBG_NIY, "%s:Skip Beacons period(%d).\n", __func__,
717 priv->join_dtim_period*XRADIO_BEACON_SKIPPING_MULTIPLIER);
718 } else {
719 pm_printk(XRADIO_DBG_NIY, "%s:Do not Skip Beacons(DTIM=%d).\n",
720 __func__, priv->join_dtim_period);
721 }
722 #endif
723
724 ret = timer_pending(&priv->mcast_timeout);
725 if (ret) {
726 pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend "
727 "mcast timeout timer_pending failed.\n", __func__);
728 goto revert3;
729 }
730
731 /* Store suspend state */
732 pm_state_vif->suspend_state = state;
733
734 return 0;
735
736 revert3:
737 xradio_resume_work(hw_priv, &priv->bss_loss_work, state->bss_loss_tmo);
738 xradio_resume_work(hw_priv, &priv->connection_loss_work,
739 state->connection_loss_tmo);
740 xradio_resume_work(hw_priv, &priv->join_timeout, state->join_tmo);
741 xradio_resume_work(hw_priv, &priv->link_id_gc_work, state->link_id_gc);
742 kfree(state);
743
744 revert2:
745 wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_off,
746 priv->if_id);
747 wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_off,
748 priv->if_id);
749 wsm_set_host_sleep(hw_priv, 0, priv->if_id);
750
751 if (priv->join_status == XRADIO_JOIN_STATUS_AP)
752 WARN_ON(wsm_set_keepalive_filter(priv, false));
753
754 #ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE
755 /* Set Multicast Address Filter */
756 if (priv->multicast_filter.numOfAddresses) {
757 priv->multicast_filter.enable = 0;
758 wsm_set_multicast_filter(hw_priv, &priv->multicast_filter,
759 priv->if_id);
760 }
761
762 /* Set Enable Broadcast Address Filter */
763 priv->broadcast_filter.action_mode = 0;
764 if (priv->join_status == XRADIO_JOIN_STATUS_AP)
765 priv->broadcast_filter.address_mode = 0;
766 xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter);
767 #endif
768
769 #ifdef MCAST_FWDING
770 fwdoffload.flags = 0x0;
771 if (priv->join_status == XRADIO_JOIN_STATUS_AP)
772 WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload, priv->if_id));
773 #endif
774
775 revert1:
776 /* up(&hw_priv->conf_lock); */
777 return -EBUSY;
778 }
779
xradio_wow_resume(struct ieee80211_hw * hw)780 int xradio_wow_resume(struct ieee80211_hw *hw)
781 {
782
783 struct xradio_common *hw_priv = hw->priv;
784 struct xradio_vif *priv;
785 int i, ret = 0;
786
787 pm_printk(XRADIO_DBG_NIY, "%s, Sleeptime=%dms\n", __func__,
788 xradio_realtime_interval(&suspend_time, &resume_time));
789
790 if (!atomic_read(&hw_priv->num_vifs))
791 pm_printk(XRADIO_DBG_WARN, "%s num_vifs=0\n", __func__);
792
793 if (hw_priv->bh_error) {
794 pm_printk(XRADIO_DBG_ERROR, "%s bh_error(%d) occurs already.\n",
795 __func__, hw_priv->bh_error);
796 }
797
798 if (atomic_read(&hw_priv->suspend_state) < XRADIO_CONNECT_SUSP) {
799 pm_printk(XRADIO_DBG_WARN, "%s not in suspend(%d).\n",
800 __func__, atomic_read(&hw_priv->suspend_state));
801 /*
802 * xradio_wow_suspend failed last time, and xradio_wow_resume is called
803 * by mac80211_reconfig in umac. return 1 to do hw restart.
804 */
805 return 1;
806 }
807
808 atomic_set(&hw_priv->suspend_lock_state, XRADIO_SUSPEND_LOCK_IDEL);
809
810 #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF
811 if (XRADIO_POWEROFF_SUSP == atomic_read(&hw_priv->suspend_state)) {
812 return xradio_poweroff_resume(hw_priv);
813 }
814 #endif
815
816 /* Disable IRQ wake */
817 hw_priv->sbus_ops->power_mgmt(hw_priv->sbus_priv, false);
818
819 up(&hw_priv->scan.lock);
820
821 /* Resume BH thread */
822 WARN_ON(xradio_bh_resume(hw_priv));
823
824 xradio_for_each_vif(hw_priv, priv, i) {
825 #ifdef P2P_MULTIVIF
826 if ((i == (XRWL_MAX_VIFS - 1)) || !priv)
827 #else
828 if (!priv)
829 #endif
830 continue;
831 ret = __xradio_wow_resume(priv);
832 if (ret) {
833 pm_printk(XRADIO_DBG_ERROR,
834 "%s:__xradio_wow_resume failed!\n", __func__);
835 break;
836 }
837 }
838
839 wsm_unlock_tx(hw_priv);
840
841 /* we always return to XRADIO_RESUME no matter errors occurs.*/
842 atomic_set(&hw_priv->suspend_state, XRADIO_RESUME);
843
844 /* Unlock configuration mutex */
845 up(&hw_priv->wsm_oper_lock);
846 up(&hw_priv->conf_lock);
847 return 0;
848 }
849
__xradio_wow_resume(struct xradio_vif * priv)850 static int __xradio_wow_resume(struct xradio_vif *priv)
851 {
852 struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv);
853 struct xradio_pm_state_vif *pm_state_vif = &priv->pm_state_vif;
854 struct xradio_suspend_state *state;
855 #ifdef MCAST_FWDING
856 struct wsm_forwarding_offload fwdoffload = {
857 .fwenable = 0x1,
858 .flags = 0x0,
859 };
860 #endif
861 pm_printk(XRADIO_DBG_NIY, "%s\n", __func__);
862
863 /* Restore suspend state */
864 state = pm_state_vif->suspend_state;
865 pm_state_vif->suspend_state = NULL;
866
867 #ifdef ROAM_OFFLOAD
868 if ((priv->vif->type == NL80211_IFTYPE_STATION)
869 && (priv->join_status == XRADIO_JOIN_STATUS_STA))
870 xradio_hw_sched_scan_stop(hw_priv);
871 #endif /*ROAM_OFFLOAD*/
872
873 if (state->beacon_skipping) {
874 #ifdef XRADIO_USE_LONG_DTIM_PERIOD
875 int join_dtim_period_extend;
876 if (priv->join_dtim_period <= 3) {
877 join_dtim_period_extend = priv->join_dtim_period * 3;
878 } else if (priv->join_dtim_period <= 5) {
879 join_dtim_period_extend = priv->join_dtim_period * 2;
880 } else {
881 join_dtim_period_extend = priv->join_dtim_period;
882 }
883 wsm_set_beacon_wakeup_period(hw_priv,
884 ((priv->beacon_int * join_dtim_period_extend) >
885 MAX_BEACON_SKIP_TIME_MS ?
886 1 : join_dtim_period_extend), 0, priv->if_id);
887 #else
888 wsm_set_beacon_wakeup_period(hw_priv,
889 (priv->beacon_int * priv->join_dtim_period >
890 MAX_BEACON_SKIP_TIME_MS) ? 1 : priv->join_dtim_period,
891 0, priv->if_id);
892 #endif
893 state->beacon_skipping = false;
894 }
895
896 if (priv->join_status == XRADIO_JOIN_STATUS_AP)
897 WARN_ON(wsm_set_keepalive_filter(priv, false));
898
899 #ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE
900 /* Set Multicast Address Filter */
901 if (priv->multicast_filter.numOfAddresses) {
902 priv->multicast_filter.enable = 0;
903 wsm_set_multicast_filter(hw_priv, &priv->multicast_filter,
904 priv->if_id);
905 }
906 /* Set Enable Broadcast Address Filter */
907 priv->broadcast_filter.action_mode = 0;
908 if (priv->join_status == XRADIO_JOIN_STATUS_AP)
909 priv->broadcast_filter.address_mode = 0;
910 xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter);
911 #endif
912
913 #ifdef MCAST_FWDING
914 if (priv->join_status == XRADIO_JOIN_STATUS_AP)
915 WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload, priv->if_id));
916 #endif
917
918 /* Resume delayed work */
919 xradio_resume_work(hw_priv, &priv->bss_loss_work, state->bss_loss_tmo);
920 xradio_resume_work(hw_priv, &priv->connection_loss_work,
921 state->connection_loss_tmo);
922 xradio_resume_work(hw_priv, &priv->join_timeout, state->join_tmo);
923 xradio_resume_work(hw_priv, &priv->link_id_gc_work, state->link_id_gc);
924
925 /* Remove UDP port filter */
926 wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_off,
927 priv->if_id);
928
929 /* Remove ethernet frame type filter */
930 wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_off,
931 priv->if_id);
932
933 /* Remove IP multicast filter */
934 wsm_set_host_sleep(hw_priv, 0, priv->if_id);
935 /* Free memory */
936 kfree(state);
937
938 return 0;
939 }
940
941 #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF
xradio_poweroff_suspend(struct xradio_common * hw_priv)942 static int xradio_poweroff_suspend(struct xradio_common *hw_priv)
943 {
944 pm_printk(XRADIO_DBG_NIY, "%s\n", __func__);
945 /* Flush all works. */
946 cancel_work_sync(&hw_priv->query_work);
947 flush_workqueue(hw_priv->workqueue);
948 flush_workqueue(hw_priv->spare_workqueue);
949
950 /* Stop serving thread */
951 if (xradio_bh_suspend(hw_priv)) {
952 pm_printk(XRADIO_DBG_WARN, "%s, xradio_bh_suspend failed!\n",
953 __func__);
954 return -EBUSY;
955 }
956
957 /* Schedule hardware restart, ensure no cmds in progress.*/
958 down(&hw_priv->wsm_cmd_sema);
959 atomic_set(&hw_priv->suspend_state, XRADIO_POWEROFF_SUSP);
960 hw_priv->hw_restart = true;
961 up(&hw_priv->wsm_cmd_sema);
962
963 /* Going to sleep with wifi power down. */
964 xradio_wlan_power(0);
965 return 0;
966 }
967
xradio_poweroff_resume(struct xradio_common * hw_priv)968 static int xradio_poweroff_resume(struct xradio_common *hw_priv)
969 {
970 pm_printk(XRADIO_DBG_NIY, "%s\n", __func__);
971 /* Revert locks */
972 wsm_unlock_tx(hw_priv);
973 up(&hw_priv->scan.lock);
974 up(&hw_priv->conf_lock);
975 up(&hw_priv->wsm_oper_lock);
976
977 down(&hw_priv->wsm_cmd_sema);
978 if (!hw_priv->exit_sync)
979 if (schedule_work(&hw_priv->hw_restart_work) <= 0)
980 pm_printk(XRADIO_DBG_ERROR, "%s restart_work failed!\n", __func__);
981 up(&hw_priv->wsm_cmd_sema);
982 return 0;
983 }
984
985
986 #endif
987