1e3ec7017SPing-Ke Shih // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2e3ec7017SPing-Ke Shih /* Copyright(c) 2019-2020  Realtek Corporation
3e3ec7017SPing-Ke Shih  */
4e3ec7017SPing-Ke Shih 
5*4843aa37SZong-Zhe Yang #include "chan.h"
6e3ec7017SPing-Ke Shih #include "coex.h"
7e3ec7017SPing-Ke Shih #include "core.h"
8e3ec7017SPing-Ke Shih #include "debug.h"
9e3ec7017SPing-Ke Shih #include "fw.h"
10e3ec7017SPing-Ke Shih #include "mac.h"
11e3ec7017SPing-Ke Shih #include "ps.h"
12e3ec7017SPing-Ke Shih #include "reg.h"
13e3ec7017SPing-Ke Shih #include "util.h"
14e3ec7017SPing-Ke Shih 
rtw89_fw_leave_lps_check(struct rtw89_dev * rtwdev,u8 macid)15e3ec7017SPing-Ke Shih static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid)
16e3ec7017SPing-Ke Shih {
17e3ec7017SPing-Ke Shih 	u32 pwr_en_bit = 0xE;
18e3ec7017SPing-Ke Shih 	u32 chk_msk = pwr_en_bit << (4 * macid);
19e3ec7017SPing-Ke Shih 	u32 polling;
20e3ec7017SPing-Ke Shih 	int ret;
21e3ec7017SPing-Ke Shih 
22e3ec7017SPing-Ke Shih 	ret = read_poll_timeout_atomic(rtw89_read32_mask, polling, !polling,
23e3ec7017SPing-Ke Shih 				       1000, 50000, false, rtwdev,
24e3ec7017SPing-Ke Shih 				       R_AX_PPWRBIT_SETTING, chk_msk);
25e3ec7017SPing-Ke Shih 	if (ret) {
26e3ec7017SPing-Ke Shih 		rtw89_info(rtwdev, "rtw89: failed to leave lps state\n");
27e3ec7017SPing-Ke Shih 		return -EBUSY;
28e3ec7017SPing-Ke Shih 	}
29e3ec7017SPing-Ke Shih 
30e3ec7017SPing-Ke Shih 	return 0;
31e3ec7017SPing-Ke Shih }
32e3ec7017SPing-Ke Shih 
rtw89_ps_power_mode_change_with_hci(struct rtw89_dev * rtwdev,bool enter)3352edbb9fSPing-Ke Shih static void rtw89_ps_power_mode_change_with_hci(struct rtw89_dev *rtwdev,
3452edbb9fSPing-Ke Shih 						bool enter)
3552edbb9fSPing-Ke Shih {
3652edbb9fSPing-Ke Shih 	ieee80211_stop_queues(rtwdev->hw);
3752edbb9fSPing-Ke Shih 	rtwdev->hci.paused = true;
3852edbb9fSPing-Ke Shih 	flush_work(&rtwdev->txq_work);
3952edbb9fSPing-Ke Shih 	ieee80211_wake_queues(rtwdev->hw);
4052edbb9fSPing-Ke Shih 
4152edbb9fSPing-Ke Shih 	rtw89_hci_pause(rtwdev, true);
4252edbb9fSPing-Ke Shih 	rtw89_mac_power_mode_change(rtwdev, enter);
4352edbb9fSPing-Ke Shih 	rtw89_hci_switch_mode(rtwdev, enter);
4452edbb9fSPing-Ke Shih 	rtw89_hci_pause(rtwdev, false);
4552edbb9fSPing-Ke Shih 
4652edbb9fSPing-Ke Shih 	rtwdev->hci.paused = false;
4752edbb9fSPing-Ke Shih 
4852edbb9fSPing-Ke Shih 	if (!enter) {
4952edbb9fSPing-Ke Shih 		local_bh_disable();
5052edbb9fSPing-Ke Shih 		napi_schedule(&rtwdev->napi);
5152edbb9fSPing-Ke Shih 		local_bh_enable();
5252edbb9fSPing-Ke Shih 	}
5352edbb9fSPing-Ke Shih }
5452edbb9fSPing-Ke Shih 
rtw89_ps_power_mode_change(struct rtw89_dev * rtwdev,bool enter)5552edbb9fSPing-Ke Shih static void rtw89_ps_power_mode_change(struct rtw89_dev *rtwdev, bool enter)
5652edbb9fSPing-Ke Shih {
5752edbb9fSPing-Ke Shih 	if (rtwdev->chip->low_power_hci_modes & BIT(rtwdev->ps_mode))
5852edbb9fSPing-Ke Shih 		rtw89_ps_power_mode_change_with_hci(rtwdev, enter);
5952edbb9fSPing-Ke Shih 	else
6052edbb9fSPing-Ke Shih 		rtw89_mac_power_mode_change(rtwdev, enter);
6152edbb9fSPing-Ke Shih }
6252edbb9fSPing-Ke Shih 
__rtw89_enter_ps_mode(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif)6319e28c7fSChin-Yen Lee void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
64e3ec7017SPing-Ke Shih {
65487b7b70SPing-Ke Shih 	if (rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT)
66487b7b70SPing-Ke Shih 		return;
67487b7b70SPing-Ke Shih 
68e3ec7017SPing-Ke Shih 	if (!rtwdev->ps_mode)
69e3ec7017SPing-Ke Shih 		return;
70e3ec7017SPing-Ke Shih 
71e3ec7017SPing-Ke Shih 	if (test_and_set_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
72e3ec7017SPing-Ke Shih 		return;
73e3ec7017SPing-Ke Shih 
7452edbb9fSPing-Ke Shih 	rtw89_ps_power_mode_change(rtwdev, true);
75e3ec7017SPing-Ke Shih }
76e3ec7017SPing-Ke Shih 
__rtw89_leave_ps_mode(struct rtw89_dev * rtwdev)77e3ec7017SPing-Ke Shih void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev)
78e3ec7017SPing-Ke Shih {
79e3ec7017SPing-Ke Shih 	if (!rtwdev->ps_mode)
80e3ec7017SPing-Ke Shih 		return;
81e3ec7017SPing-Ke Shih 
82e3ec7017SPing-Ke Shih 	if (test_and_clear_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
8352edbb9fSPing-Ke Shih 		rtw89_ps_power_mode_change(rtwdev, false);
84e3ec7017SPing-Ke Shih }
85e3ec7017SPing-Ke Shih 
__rtw89_enter_lps(struct rtw89_dev * rtwdev,u8 mac_id)86e3ec7017SPing-Ke Shih static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id)
87e3ec7017SPing-Ke Shih {
88e3ec7017SPing-Ke Shih 	struct rtw89_lps_parm lps_param = {
89e3ec7017SPing-Ke Shih 		.macid = mac_id,
90e3ec7017SPing-Ke Shih 		.psmode = RTW89_MAC_AX_PS_MODE_LEGACY,
91e3ec7017SPing-Ke Shih 		.lastrpwm = RTW89_LAST_RPWM_PS,
92e3ec7017SPing-Ke Shih 	};
93e3ec7017SPing-Ke Shih 
94e3ec7017SPing-Ke Shih 	rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL);
95e3ec7017SPing-Ke Shih 	rtw89_fw_h2c_lps_parm(rtwdev, &lps_param);
96e3ec7017SPing-Ke Shih }
97e3ec7017SPing-Ke Shih 
__rtw89_leave_lps(struct rtw89_dev * rtwdev,u8 mac_id)98e3ec7017SPing-Ke Shih static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, u8 mac_id)
99e3ec7017SPing-Ke Shih {
100e3ec7017SPing-Ke Shih 	struct rtw89_lps_parm lps_param = {
101e3ec7017SPing-Ke Shih 		.macid = mac_id,
102e3ec7017SPing-Ke Shih 		.psmode = RTW89_MAC_AX_PS_MODE_ACTIVE,
103e3ec7017SPing-Ke Shih 		.lastrpwm = RTW89_LAST_RPWM_ACTIVE,
104e3ec7017SPing-Ke Shih 	};
105e3ec7017SPing-Ke Shih 
106e3ec7017SPing-Ke Shih 	rtw89_fw_h2c_lps_parm(rtwdev, &lps_param);
107e3ec7017SPing-Ke Shih 	rtw89_fw_leave_lps_check(rtwdev, 0);
108e3ec7017SPing-Ke Shih 	rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON);
109e3ec7017SPing-Ke Shih }
110e3ec7017SPing-Ke Shih 
rtw89_leave_ps_mode(struct rtw89_dev * rtwdev)111e3ec7017SPing-Ke Shih void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev)
112e3ec7017SPing-Ke Shih {
113e3ec7017SPing-Ke Shih 	lockdep_assert_held(&rtwdev->mutex);
114e3ec7017SPing-Ke Shih 
115e3ec7017SPing-Ke Shih 	__rtw89_leave_ps_mode(rtwdev);
116e3ec7017SPing-Ke Shih }
117e3ec7017SPing-Ke Shih 
rtw89_enter_lps(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif,bool ps_mode)118deb1b2aeSChih-Kang Chang void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
119deb1b2aeSChih-Kang Chang 		     bool ps_mode)
120e3ec7017SPing-Ke Shih {
121e3ec7017SPing-Ke Shih 	lockdep_assert_held(&rtwdev->mutex);
122e3ec7017SPing-Ke Shih 
123e3ec7017SPing-Ke Shih 	if (test_and_set_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags))
124e3ec7017SPing-Ke Shih 		return;
125e3ec7017SPing-Ke Shih 
126487b7b70SPing-Ke Shih 	__rtw89_enter_lps(rtwdev, rtwvif->mac_id);
127deb1b2aeSChih-Kang Chang 	if (ps_mode)
128487b7b70SPing-Ke Shih 		__rtw89_enter_ps_mode(rtwdev, rtwvif);
129e3ec7017SPing-Ke Shih }
130e3ec7017SPing-Ke Shih 
rtw89_leave_lps_vif(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif)131e3ec7017SPing-Ke Shih static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
132e3ec7017SPing-Ke Shih {
133487b7b70SPing-Ke Shih 	if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION &&
134487b7b70SPing-Ke Shih 	    rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT)
135e3ec7017SPing-Ke Shih 		return;
136e3ec7017SPing-Ke Shih 
137e3ec7017SPing-Ke Shih 	__rtw89_leave_lps(rtwdev, rtwvif->mac_id);
138e3ec7017SPing-Ke Shih }
139e3ec7017SPing-Ke Shih 
rtw89_leave_lps(struct rtw89_dev * rtwdev)140e3ec7017SPing-Ke Shih void rtw89_leave_lps(struct rtw89_dev *rtwdev)
141e3ec7017SPing-Ke Shih {
142e3ec7017SPing-Ke Shih 	struct rtw89_vif *rtwvif;
143e3ec7017SPing-Ke Shih 
144e3ec7017SPing-Ke Shih 	lockdep_assert_held(&rtwdev->mutex);
145e3ec7017SPing-Ke Shih 
146e3ec7017SPing-Ke Shih 	if (!test_and_clear_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags))
147e3ec7017SPing-Ke Shih 		return;
148e3ec7017SPing-Ke Shih 
149674ece27SZong-Zhe Yang 	__rtw89_leave_ps_mode(rtwdev);
150674ece27SZong-Zhe Yang 
151e3ec7017SPing-Ke Shih 	rtw89_for_each_rtwvif(rtwdev, rtwvif)
152e3ec7017SPing-Ke Shih 		rtw89_leave_lps_vif(rtwdev, rtwvif);
153e3ec7017SPing-Ke Shih }
154e3ec7017SPing-Ke Shih 
rtw89_enter_ips(struct rtw89_dev * rtwdev)155e3ec7017SPing-Ke Shih void rtw89_enter_ips(struct rtw89_dev *rtwdev)
156e3ec7017SPing-Ke Shih {
157e3ec7017SPing-Ke Shih 	struct rtw89_vif *rtwvif;
158e3ec7017SPing-Ke Shih 
159e3ec7017SPing-Ke Shih 	set_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags);
160e3ec7017SPing-Ke Shih 
1616cfb6cc2SPo-Hao Huang 	if (!test_bit(RTW89_FLAG_POWERON, rtwdev->flags))
1626cfb6cc2SPo-Hao Huang 		return;
1636cfb6cc2SPo-Hao Huang 
164e3ec7017SPing-Ke Shih 	rtw89_for_each_rtwvif(rtwdev, rtwvif)
165e3ec7017SPing-Ke Shih 		rtw89_mac_vif_deinit(rtwdev, rtwvif);
166e3ec7017SPing-Ke Shih 
167e3ec7017SPing-Ke Shih 	rtw89_core_stop(rtwdev);
168e3ec7017SPing-Ke Shih }
169e3ec7017SPing-Ke Shih 
rtw89_leave_ips(struct rtw89_dev * rtwdev)170e3ec7017SPing-Ke Shih void rtw89_leave_ips(struct rtw89_dev *rtwdev)
171e3ec7017SPing-Ke Shih {
172e3ec7017SPing-Ke Shih 	struct rtw89_vif *rtwvif;
173e3ec7017SPing-Ke Shih 	int ret;
174e3ec7017SPing-Ke Shih 
1756cfb6cc2SPo-Hao Huang 	if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags))
1766cfb6cc2SPo-Hao Huang 		return;
1776cfb6cc2SPo-Hao Huang 
178e3ec7017SPing-Ke Shih 	ret = rtw89_core_start(rtwdev);
179e3ec7017SPing-Ke Shih 	if (ret)
180e3ec7017SPing-Ke Shih 		rtw89_err(rtwdev, "failed to leave idle state\n");
181e3ec7017SPing-Ke Shih 
182e3ec7017SPing-Ke Shih 	rtw89_set_channel(rtwdev);
183e3ec7017SPing-Ke Shih 
184e3ec7017SPing-Ke Shih 	rtw89_for_each_rtwvif(rtwdev, rtwvif)
185e3ec7017SPing-Ke Shih 		rtw89_mac_vif_init(rtwdev, rtwvif);
186e3ec7017SPing-Ke Shih 
187e3ec7017SPing-Ke Shih 	clear_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags);
188e3ec7017SPing-Ke Shih }
189e3ec7017SPing-Ke Shih 
rtw89_set_coex_ctrl_lps(struct rtw89_dev * rtwdev,bool btc_ctrl)190e3ec7017SPing-Ke Shih void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl)
191e3ec7017SPing-Ke Shih {
192e3ec7017SPing-Ke Shih 	if (btc_ctrl)
193e3ec7017SPing-Ke Shih 		rtw89_leave_lps(rtwdev);
194e3ec7017SPing-Ke Shih }
195f4a43c3bSDian-Syuan Yang 
rtw89_tsf32_toggle(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif,enum rtw89_p2pps_action act)196f4a43c3bSDian-Syuan Yang static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
197f4a43c3bSDian-Syuan Yang 			       enum rtw89_p2pps_action act)
198f4a43c3bSDian-Syuan Yang {
199f4a43c3bSDian-Syuan Yang 	if (act == RTW89_P2P_ACT_UPDATE || act == RTW89_P2P_ACT_REMOVE)
200f4a43c3bSDian-Syuan Yang 		return;
201f4a43c3bSDian-Syuan Yang 
202f4a43c3bSDian-Syuan Yang 	if (act == RTW89_P2P_ACT_INIT)
203f4a43c3bSDian-Syuan Yang 		rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, true);
204f4a43c3bSDian-Syuan Yang 	else if (act == RTW89_P2P_ACT_TERMINATE)
205f4a43c3bSDian-Syuan Yang 		rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, false);
206f4a43c3bSDian-Syuan Yang }
207f4a43c3bSDian-Syuan Yang 
rtw89_p2p_disable_all_noa(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif)208f4a43c3bSDian-Syuan Yang static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev,
209f4a43c3bSDian-Syuan Yang 				      struct ieee80211_vif *vif)
210f4a43c3bSDian-Syuan Yang {
211f4a43c3bSDian-Syuan Yang 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
212f4a43c3bSDian-Syuan Yang 	enum rtw89_p2pps_action act;
213f4a43c3bSDian-Syuan Yang 	u8 noa_id;
214f4a43c3bSDian-Syuan Yang 
215f4a43c3bSDian-Syuan Yang 	if (rtwvif->last_noa_nr == 0)
216f4a43c3bSDian-Syuan Yang 		return;
217f4a43c3bSDian-Syuan Yang 
218f4a43c3bSDian-Syuan Yang 	for (noa_id = 0; noa_id < rtwvif->last_noa_nr; noa_id++) {
219f4a43c3bSDian-Syuan Yang 		if (noa_id == rtwvif->last_noa_nr - 1)
220f4a43c3bSDian-Syuan Yang 			act = RTW89_P2P_ACT_TERMINATE;
221f4a43c3bSDian-Syuan Yang 		else
222f4a43c3bSDian-Syuan Yang 			act = RTW89_P2P_ACT_REMOVE;
223f4a43c3bSDian-Syuan Yang 		rtw89_tsf32_toggle(rtwdev, rtwvif, act);
224f4a43c3bSDian-Syuan Yang 		rtw89_fw_h2c_p2p_act(rtwdev, vif, NULL, act, noa_id);
225f4a43c3bSDian-Syuan Yang 	}
226f4a43c3bSDian-Syuan Yang }
227f4a43c3bSDian-Syuan Yang 
rtw89_p2p_update_noa(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif)228f4a43c3bSDian-Syuan Yang static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev,
229f4a43c3bSDian-Syuan Yang 				 struct ieee80211_vif *vif)
230f4a43c3bSDian-Syuan Yang {
231f4a43c3bSDian-Syuan Yang 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
232f4a43c3bSDian-Syuan Yang 	struct ieee80211_p2p_noa_desc *desc;
233f4a43c3bSDian-Syuan Yang 	enum rtw89_p2pps_action act;
234f4a43c3bSDian-Syuan Yang 	u8 noa_id;
235f4a43c3bSDian-Syuan Yang 
236f4a43c3bSDian-Syuan Yang 	for (noa_id = 0; noa_id < RTW89_P2P_MAX_NOA_NUM; noa_id++) {
237f4a43c3bSDian-Syuan Yang 		desc = &vif->bss_conf.p2p_noa_attr.desc[noa_id];
238f4a43c3bSDian-Syuan Yang 		if (!desc->count || !desc->duration)
239f4a43c3bSDian-Syuan Yang 			break;
240f4a43c3bSDian-Syuan Yang 
241f4a43c3bSDian-Syuan Yang 		if (noa_id == 0)
242f4a43c3bSDian-Syuan Yang 			act = RTW89_P2P_ACT_INIT;
243f4a43c3bSDian-Syuan Yang 		else
244f4a43c3bSDian-Syuan Yang 			act = RTW89_P2P_ACT_UPDATE;
245f4a43c3bSDian-Syuan Yang 		rtw89_tsf32_toggle(rtwdev, rtwvif, act);
246f4a43c3bSDian-Syuan Yang 		rtw89_fw_h2c_p2p_act(rtwdev, vif, desc, act, noa_id);
247f4a43c3bSDian-Syuan Yang 	}
248f4a43c3bSDian-Syuan Yang 	rtwvif->last_noa_nr = noa_id;
249f4a43c3bSDian-Syuan Yang }
250f4a43c3bSDian-Syuan Yang 
rtw89_process_p2p_ps(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif)251f4a43c3bSDian-Syuan Yang void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
252f4a43c3bSDian-Syuan Yang {
253f4a43c3bSDian-Syuan Yang 	rtw89_p2p_disable_all_noa(rtwdev, vif);
254f4a43c3bSDian-Syuan Yang 	rtw89_p2p_update_noa(rtwdev, vif);
255f4a43c3bSDian-Syuan Yang }
25626a125f5SPing-Ke Shih 
rtw89_recalc_lps(struct rtw89_dev * rtwdev)25726a125f5SPing-Ke Shih void rtw89_recalc_lps(struct rtw89_dev *rtwdev)
25826a125f5SPing-Ke Shih {
25926a125f5SPing-Ke Shih 	struct ieee80211_vif *vif, *found_vif = NULL;
26026a125f5SPing-Ke Shih 	struct rtw89_vif *rtwvif;
261*4843aa37SZong-Zhe Yang 	enum rtw89_entity_mode mode;
26226a125f5SPing-Ke Shih 	int count = 0;
26326a125f5SPing-Ke Shih 
264*4843aa37SZong-Zhe Yang 	mode = rtw89_get_entity_mode(rtwdev);
265*4843aa37SZong-Zhe Yang 	if (mode == RTW89_ENTITY_MODE_MCC)
266*4843aa37SZong-Zhe Yang 		goto disable_lps;
267*4843aa37SZong-Zhe Yang 
26826a125f5SPing-Ke Shih 	rtw89_for_each_rtwvif(rtwdev, rtwvif) {
26926a125f5SPing-Ke Shih 		vif = rtwvif_to_vif(rtwvif);
27026a125f5SPing-Ke Shih 
27126a125f5SPing-Ke Shih 		if (vif->type != NL80211_IFTYPE_STATION) {
27226a125f5SPing-Ke Shih 			count = 0;
27326a125f5SPing-Ke Shih 			break;
27426a125f5SPing-Ke Shih 		}
27526a125f5SPing-Ke Shih 
27626a125f5SPing-Ke Shih 		count++;
27726a125f5SPing-Ke Shih 		found_vif = vif;
27826a125f5SPing-Ke Shih 	}
27926a125f5SPing-Ke Shih 
28026a125f5SPing-Ke Shih 	if (count == 1 && found_vif->cfg.ps) {
28126a125f5SPing-Ke Shih 		rtwdev->lps_enabled = true;
282*4843aa37SZong-Zhe Yang 		return;
283*4843aa37SZong-Zhe Yang 	}
284*4843aa37SZong-Zhe Yang 
285*4843aa37SZong-Zhe Yang disable_lps:
28626a125f5SPing-Ke Shih 	rtw89_leave_lps(rtwdev);
28726a125f5SPing-Ke Shih 	rtwdev->lps_enabled = false;
28826a125f5SPing-Ke Shih }
28951383fd7SZong-Zhe Yang 
rtw89_p2p_noa_renew(struct rtw89_vif * rtwvif)29051383fd7SZong-Zhe Yang void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif)
29151383fd7SZong-Zhe Yang {
29251383fd7SZong-Zhe Yang 	struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa;
29351383fd7SZong-Zhe Yang 	struct rtw89_p2p_noa_ie *ie = &setter->ie;
29451383fd7SZong-Zhe Yang 	struct rtw89_p2p_ie_head *p2p_head = &ie->p2p_head;
29551383fd7SZong-Zhe Yang 	struct rtw89_noa_attr_head *noa_head = &ie->noa_head;
29651383fd7SZong-Zhe Yang 
29751383fd7SZong-Zhe Yang 	if (setter->noa_count) {
29851383fd7SZong-Zhe Yang 		setter->noa_index++;
29951383fd7SZong-Zhe Yang 		setter->noa_count = 0;
30051383fd7SZong-Zhe Yang 	}
30151383fd7SZong-Zhe Yang 
30251383fd7SZong-Zhe Yang 	memset(ie, 0, sizeof(*ie));
30351383fd7SZong-Zhe Yang 
30451383fd7SZong-Zhe Yang 	p2p_head->eid = WLAN_EID_VENDOR_SPECIFIC;
30551383fd7SZong-Zhe Yang 	p2p_head->ie_len = 4 + sizeof(*noa_head);
30651383fd7SZong-Zhe Yang 	p2p_head->oui[0] = (WLAN_OUI_WFA >> 16) & 0xff;
30751383fd7SZong-Zhe Yang 	p2p_head->oui[1] = (WLAN_OUI_WFA >> 8) & 0xff;
30851383fd7SZong-Zhe Yang 	p2p_head->oui[2] = (WLAN_OUI_WFA >> 0) & 0xff;
30951383fd7SZong-Zhe Yang 	p2p_head->oui_type = WLAN_OUI_TYPE_WFA_P2P;
31051383fd7SZong-Zhe Yang 
31151383fd7SZong-Zhe Yang 	noa_head->attr_type = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;
31251383fd7SZong-Zhe Yang 	noa_head->attr_len = cpu_to_le16(2);
31351383fd7SZong-Zhe Yang 	noa_head->index = setter->noa_index;
31451383fd7SZong-Zhe Yang 	noa_head->oppps_ctwindow = 0;
31551383fd7SZong-Zhe Yang }
31651383fd7SZong-Zhe Yang 
rtw89_p2p_noa_append(struct rtw89_vif * rtwvif,const struct ieee80211_p2p_noa_desc * desc)31751383fd7SZong-Zhe Yang void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif,
31851383fd7SZong-Zhe Yang 			  const struct ieee80211_p2p_noa_desc *desc)
31951383fd7SZong-Zhe Yang {
32051383fd7SZong-Zhe Yang 	struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa;
32151383fd7SZong-Zhe Yang 	struct rtw89_p2p_noa_ie *ie = &setter->ie;
32251383fd7SZong-Zhe Yang 	struct rtw89_p2p_ie_head *p2p_head = &ie->p2p_head;
32351383fd7SZong-Zhe Yang 	struct rtw89_noa_attr_head *noa_head = &ie->noa_head;
32451383fd7SZong-Zhe Yang 
32551383fd7SZong-Zhe Yang 	if (!desc->count || !desc->duration)
32651383fd7SZong-Zhe Yang 		return;
32751383fd7SZong-Zhe Yang 
32851383fd7SZong-Zhe Yang 	if (setter->noa_count >= RTW89_P2P_MAX_NOA_NUM)
32951383fd7SZong-Zhe Yang 		return;
33051383fd7SZong-Zhe Yang 
33151383fd7SZong-Zhe Yang 	p2p_head->ie_len += sizeof(*desc);
33251383fd7SZong-Zhe Yang 	le16_add_cpu(&noa_head->attr_len, sizeof(*desc));
33351383fd7SZong-Zhe Yang 
33451383fd7SZong-Zhe Yang 	ie->noa_desc[setter->noa_count++] = *desc;
33551383fd7SZong-Zhe Yang }
33651383fd7SZong-Zhe Yang 
rtw89_p2p_noa_fetch(struct rtw89_vif * rtwvif,void ** data)33751383fd7SZong-Zhe Yang u8 rtw89_p2p_noa_fetch(struct rtw89_vif *rtwvif, void **data)
33851383fd7SZong-Zhe Yang {
33951383fd7SZong-Zhe Yang 	struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa;
34051383fd7SZong-Zhe Yang 	struct rtw89_p2p_noa_ie *ie = &setter->ie;
34151383fd7SZong-Zhe Yang 	void *tail;
34251383fd7SZong-Zhe Yang 
34351383fd7SZong-Zhe Yang 	if (!setter->noa_count)
34451383fd7SZong-Zhe Yang 		return 0;
34551383fd7SZong-Zhe Yang 
34651383fd7SZong-Zhe Yang 	*data = ie;
34751383fd7SZong-Zhe Yang 	tail = ie->noa_desc + setter->noa_count;
34851383fd7SZong-Zhe Yang 	return tail - *data;
34951383fd7SZong-Zhe Yang }
350