]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/net/wireless/realtek/rtw88/ps.c
ffba3bd7bb316c936822275e783aa8ac7f4b4b94
[linux.git] / drivers / net / wireless / realtek / rtw88 / ps.c
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2018-2019  Realtek Corporation
3  */
4
5 #include "main.h"
6 #include "fw.h"
7 #include "ps.h"
8 #include "mac.h"
9 #include "coex.h"
10 #include "debug.h"
11
12 static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
13 {
14         int ret;
15
16         ret = rtw_core_start(rtwdev);
17         if (ret)
18                 rtw_err(rtwdev, "leave idle state failed\n");
19
20         rtw_set_channel(rtwdev);
21         clear_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
22
23         return ret;
24 }
25
26 int rtw_enter_ips(struct rtw_dev *rtwdev)
27 {
28         set_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
29
30         rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
31
32         rtw_core_stop(rtwdev);
33
34         return 0;
35 }
36
37 static void rtw_restore_port_cfg_iter(void *data, u8 *mac,
38                                       struct ieee80211_vif *vif)
39 {
40         struct rtw_dev *rtwdev = data;
41         struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
42         u32 config = ~0;
43
44         rtw_vif_port_config(rtwdev, rtwvif, config);
45 }
46
47 int rtw_leave_ips(struct rtw_dev *rtwdev)
48 {
49         int ret;
50
51         ret = rtw_ips_pwr_up(rtwdev);
52         if (ret) {
53                 rtw_err(rtwdev, "failed to leave ips state\n");
54                 return ret;
55         }
56
57         rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
58
59         rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
60
61         return 0;
62 }
63
64 static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
65 {
66         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
67
68         conf->state = RTW_ALL_ON;
69         conf->awake_interval = 1;
70         conf->rlbm = 0;
71         conf->smart_ps = 0;
72
73         rtw_fw_set_pwr_mode(rtwdev);
74         clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
75
76         rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);
77 }
78
79 static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
80 {
81         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
82
83         conf->state = RTW_RF_OFF;
84         conf->awake_interval = 1;
85         conf->rlbm = 1;
86         conf->smart_ps = 2;
87
88         rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
89
90         rtw_fw_set_pwr_mode(rtwdev);
91         set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
92 }
93
94 bool rtw_in_lps(struct rtw_dev *rtwdev)
95 {
96         return test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
97 }
98
99 void rtw_enter_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif)
100 {
101         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
102
103         if (WARN_ON(!rtwvif))
104                 return;
105
106         if (rtwvif->in_lps)
107                 return;
108
109         conf->mode = RTW_MODE_LPS;
110         conf->rtwvif = rtwvif;
111         rtwvif->in_lps = true;
112
113         rtw_enter_lps_core(rtwdev);
114 }
115
116 void rtw_leave_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif)
117 {
118         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
119
120         if (WARN_ON(!rtwvif))
121                 return;
122
123         if (!rtwvif->in_lps)
124                 return;
125
126         conf->mode = RTW_MODE_ACTIVE;
127         conf->rtwvif = rtwvif;
128         rtwvif->in_lps = false;
129
130         rtw_leave_lps_core(rtwdev);
131 }