xref: /linux/drivers/net/wireless/realtek/rtw89/ps.c (revision dd093fb0)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2019-2020  Realtek Corporation
3  */
4 
5 #include "coex.h"
6 #include "core.h"
7 #include "debug.h"
8 #include "fw.h"
9 #include "mac.h"
10 #include "ps.h"
11 #include "reg.h"
12 #include "util.h"
13 
14 static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid)
15 {
16 	u32 pwr_en_bit = 0xE;
17 	u32 chk_msk = pwr_en_bit << (4 * macid);
18 	u32 polling;
19 	int ret;
20 
21 	ret = read_poll_timeout_atomic(rtw89_read32_mask, polling, !polling,
22 				       1000, 50000, false, rtwdev,
23 				       R_AX_PPWRBIT_SETTING, chk_msk);
24 	if (ret) {
25 		rtw89_info(rtwdev, "rtw89: failed to leave lps state\n");
26 		return -EBUSY;
27 	}
28 
29 	return 0;
30 }
31 
32 static void rtw89_ps_power_mode_change_with_hci(struct rtw89_dev *rtwdev,
33 						bool enter)
34 {
35 	ieee80211_stop_queues(rtwdev->hw);
36 	rtwdev->hci.paused = true;
37 	flush_work(&rtwdev->txq_work);
38 	ieee80211_wake_queues(rtwdev->hw);
39 
40 	rtw89_hci_pause(rtwdev, true);
41 	rtw89_mac_power_mode_change(rtwdev, enter);
42 	rtw89_hci_switch_mode(rtwdev, enter);
43 	rtw89_hci_pause(rtwdev, false);
44 
45 	rtwdev->hci.paused = false;
46 
47 	if (!enter) {
48 		local_bh_disable();
49 		napi_schedule(&rtwdev->napi);
50 		local_bh_enable();
51 	}
52 }
53 
54 static void rtw89_ps_power_mode_change(struct rtw89_dev *rtwdev, bool enter)
55 {
56 	if (rtwdev->chip->low_power_hci_modes & BIT(rtwdev->ps_mode))
57 		rtw89_ps_power_mode_change_with_hci(rtwdev, enter);
58 	else
59 		rtw89_mac_power_mode_change(rtwdev, enter);
60 }
61 
62 void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
63 {
64 	if (rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT)
65 		return;
66 
67 	if (!rtwdev->ps_mode)
68 		return;
69 
70 	if (test_and_set_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
71 		return;
72 
73 	rtw89_ps_power_mode_change(rtwdev, true);
74 }
75 
76 void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev)
77 {
78 	if (!rtwdev->ps_mode)
79 		return;
80 
81 	if (test_and_clear_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
82 		rtw89_ps_power_mode_change(rtwdev, false);
83 }
84 
85 static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id)
86 {
87 	struct rtw89_lps_parm lps_param = {
88 		.macid = mac_id,
89 		.psmode = RTW89_MAC_AX_PS_MODE_LEGACY,
90 		.lastrpwm = RTW89_LAST_RPWM_PS,
91 	};
92 
93 	rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL);
94 	rtw89_fw_h2c_lps_parm(rtwdev, &lps_param);
95 }
96 
97 static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, u8 mac_id)
98 {
99 	struct rtw89_lps_parm lps_param = {
100 		.macid = mac_id,
101 		.psmode = RTW89_MAC_AX_PS_MODE_ACTIVE,
102 		.lastrpwm = RTW89_LAST_RPWM_ACTIVE,
103 	};
104 
105 	rtw89_fw_h2c_lps_parm(rtwdev, &lps_param);
106 	rtw89_fw_leave_lps_check(rtwdev, 0);
107 	rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON);
108 }
109 
110 void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev)
111 {
112 	lockdep_assert_held(&rtwdev->mutex);
113 
114 	__rtw89_leave_ps_mode(rtwdev);
115 }
116 
117 void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
118 {
119 	lockdep_assert_held(&rtwdev->mutex);
120 
121 	if (test_and_set_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags))
122 		return;
123 
124 	__rtw89_enter_lps(rtwdev, rtwvif->mac_id);
125 	__rtw89_enter_ps_mode(rtwdev, rtwvif);
126 }
127 
128 static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
129 {
130 	if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION &&
131 	    rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT)
132 		return;
133 
134 	__rtw89_leave_lps(rtwdev, rtwvif->mac_id);
135 }
136 
137 void rtw89_leave_lps(struct rtw89_dev *rtwdev)
138 {
139 	struct rtw89_vif *rtwvif;
140 
141 	lockdep_assert_held(&rtwdev->mutex);
142 
143 	if (!test_and_clear_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags))
144 		return;
145 
146 	__rtw89_leave_ps_mode(rtwdev);
147 
148 	rtw89_for_each_rtwvif(rtwdev, rtwvif)
149 		rtw89_leave_lps_vif(rtwdev, rtwvif);
150 }
151 
152 void rtw89_enter_ips(struct rtw89_dev *rtwdev)
153 {
154 	struct rtw89_vif *rtwvif;
155 
156 	set_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags);
157 
158 	rtw89_for_each_rtwvif(rtwdev, rtwvif)
159 		rtw89_mac_vif_deinit(rtwdev, rtwvif);
160 
161 	rtw89_core_stop(rtwdev);
162 }
163 
164 void rtw89_leave_ips(struct rtw89_dev *rtwdev)
165 {
166 	struct rtw89_vif *rtwvif;
167 	int ret;
168 
169 	ret = rtw89_core_start(rtwdev);
170 	if (ret)
171 		rtw89_err(rtwdev, "failed to leave idle state\n");
172 
173 	rtw89_set_channel(rtwdev);
174 
175 	rtw89_for_each_rtwvif(rtwdev, rtwvif)
176 		rtw89_mac_vif_init(rtwdev, rtwvif);
177 
178 	clear_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags);
179 }
180 
181 void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl)
182 {
183 	if (btc_ctrl)
184 		rtw89_leave_lps(rtwdev);
185 }
186 
187 static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
188 			       enum rtw89_p2pps_action act)
189 {
190 	if (act == RTW89_P2P_ACT_UPDATE || act == RTW89_P2P_ACT_REMOVE)
191 		return;
192 
193 	if (act == RTW89_P2P_ACT_INIT)
194 		rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, true);
195 	else if (act == RTW89_P2P_ACT_TERMINATE)
196 		rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, false);
197 }
198 
199 static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev,
200 				      struct ieee80211_vif *vif)
201 {
202 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
203 	enum rtw89_p2pps_action act;
204 	u8 noa_id;
205 
206 	if (rtwvif->last_noa_nr == 0)
207 		return;
208 
209 	for (noa_id = 0; noa_id < rtwvif->last_noa_nr; noa_id++) {
210 		if (noa_id == rtwvif->last_noa_nr - 1)
211 			act = RTW89_P2P_ACT_TERMINATE;
212 		else
213 			act = RTW89_P2P_ACT_REMOVE;
214 		rtw89_tsf32_toggle(rtwdev, rtwvif, act);
215 		rtw89_fw_h2c_p2p_act(rtwdev, vif, NULL, act, noa_id);
216 	}
217 }
218 
219 static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev,
220 				 struct ieee80211_vif *vif)
221 {
222 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
223 	struct ieee80211_p2p_noa_desc *desc;
224 	enum rtw89_p2pps_action act;
225 	u8 noa_id;
226 
227 	for (noa_id = 0; noa_id < RTW89_P2P_MAX_NOA_NUM; noa_id++) {
228 		desc = &vif->bss_conf.p2p_noa_attr.desc[noa_id];
229 		if (!desc->count || !desc->duration)
230 			break;
231 
232 		if (noa_id == 0)
233 			act = RTW89_P2P_ACT_INIT;
234 		else
235 			act = RTW89_P2P_ACT_UPDATE;
236 		rtw89_tsf32_toggle(rtwdev, rtwvif, act);
237 		rtw89_fw_h2c_p2p_act(rtwdev, vif, desc, act, noa_id);
238 	}
239 	rtwvif->last_noa_nr = noa_id;
240 }
241 
242 void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
243 {
244 	rtw89_p2p_disable_all_noa(rtwdev, vif);
245 	rtw89_p2p_update_noa(rtwdev, vif);
246 }
247