xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852bs/phl/phl_cmd_ps.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * Copyright(c) 2021 Realtek Corporation.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify it
6*4882a593Smuzhiyun  * under the terms of version 2 of the GNU General Public License as
7*4882a593Smuzhiyun  * published by the Free Software Foundation.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful, but WITHOUT
10*4882a593Smuzhiyun  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12*4882a593Smuzhiyun  * more details.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *****************************************************************************/
15*4882a593Smuzhiyun #define _PHL_CMD_PS_C_
16*4882a593Smuzhiyun #include "phl_headers.h"
17*4882a593Smuzhiyun #ifdef CONFIG_POWER_SAVE
18*4882a593Smuzhiyun /* structure of a power request */
19*4882a593Smuzhiyun struct pwr_req {
20*4882a593Smuzhiyun 	_os_list list;
21*4882a593Smuzhiyun 	u16 evt_id;
22*4882a593Smuzhiyun };
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun struct rt_ps {
25*4882a593Smuzhiyun 	enum phl_ps_rt_rson rt_rson;
26*4882a593Smuzhiyun 	bool ps_allow;
27*4882a593Smuzhiyun };
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun enum {
30*4882a593Smuzhiyun 	PS_STATE_NONE = 0,
31*4882a593Smuzhiyun 	PS_STATE_LEAVED,
32*4882a593Smuzhiyun 	/**
33*4882a593Smuzhiyun 	 * lps: protocol only
34*4882a593Smuzhiyun 	 * ips: won't in this state
35*4882a593Smuzhiyun 	 */
36*4882a593Smuzhiyun 	PS_STATE_PROTO,
37*4882a593Smuzhiyun 	/**
38*4882a593Smuzhiyun 	 * lps: protocol + power
39*4882a593Smuzhiyun 	 * ips: power
40*4882a593Smuzhiyun 	 */
41*4882a593Smuzhiyun 	PS_STATE_ENTERED
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
_ps_state_to_str(u8 ps_state)44*4882a593Smuzhiyun static const char *_ps_state_to_str(u8 ps_state)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	switch (ps_state) {
47*4882a593Smuzhiyun 	case PS_STATE_ENTERED:
48*4882a593Smuzhiyun 		return "PS_ENTERED";
49*4882a593Smuzhiyun 	case PS_STATE_PROTO:
50*4882a593Smuzhiyun 		return "PS_PROTOCOL";
51*4882a593Smuzhiyun 	case PS_STATE_LEAVED:
52*4882a593Smuzhiyun 		return "PS_LEAVED";
53*4882a593Smuzhiyun 	default:
54*4882a593Smuzhiyun 		return "NONE";
55*4882a593Smuzhiyun 	}
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun struct _ps_mr_info {
59*4882a593Smuzhiyun 	bool ap_active;
60*4882a593Smuzhiyun 	bool gc_active;
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #define CMD_PS_TIMER_PERIOD 100
64*4882a593Smuzhiyun #define MAX_PWE_REQ_NUM 16
65*4882a593Smuzhiyun struct cmd_ps {
66*4882a593Smuzhiyun 	struct phl_info_t *phl_info;
67*4882a593Smuzhiyun 	void *dispr;
68*4882a593Smuzhiyun 	_os_timer ps_timer;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	struct phl_queue req_busy_q;
71*4882a593Smuzhiyun 	struct phl_queue req_idle_q;
72*4882a593Smuzhiyun 	struct pwr_req req_pool[MAX_PWE_REQ_NUM];
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	bool rej_pwr_req; /* reject all pwr request */
75*4882a593Smuzhiyun 	bool btc_req_pwr; /* btc request pwr or not */
76*4882a593Smuzhiyun 	bool stop_datapath;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	/* current state */
79*4882a593Smuzhiyun 	u8 cur_pwr_lvl;
80*4882a593Smuzhiyun 	u8 ps_state;
81*4882a593Smuzhiyun 	u8 ps_mode;
82*4882a593Smuzhiyun 	char enter_rson[MAX_CMD_PS_RSON_LENGTH];
83*4882a593Smuzhiyun 	char leave_rson[MAX_CMD_PS_RSON_LENGTH];
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	struct rtw_phl_stainfo_t *sta; /* sta entering/leaving ps */
86*4882a593Smuzhiyun 	u16 macid;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	/* lps */
89*4882a593Smuzhiyun 	u32 null_token;
90*4882a593Smuzhiyun 	bool wdg_leave_ps;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	/* refs. enum "phl_ps_rt_rson" */
93*4882a593Smuzhiyun 	enum phl_ps_rt_rson rt_stop_rson;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	struct _ps_mr_info mr_info;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	/* rssi */
98*4882a593Smuzhiyun 	u8 rssi_bcn_min;
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun /**
102*4882a593Smuzhiyun  * determine leave lps or not
103*4882a593Smuzhiyun  * return true if rssi variation reach threshold
104*4882a593Smuzhiyun  * @ps: see cmd_ps
105*4882a593Smuzhiyun  */
_chk_rssi_diff_reach_thld(struct cmd_ps * ps)106*4882a593Smuzhiyun static bool _chk_rssi_diff_reach_thld(struct cmd_ps *ps)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	struct phl_info_t *phl_info = ps->phl_info;
109*4882a593Smuzhiyun 	struct rtw_ps_cap_t *ps_cap = _get_ps_cap(ps->phl_info);
110*4882a593Smuzhiyun 	u8 cur_rssi_bcn_min = 0;
111*4882a593Smuzhiyun 	u8 *rssi_bcn_min = &ps->rssi_bcn_min;
112*4882a593Smuzhiyun 	bool leave_ps = false;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	cur_rssi_bcn_min = phl_get_min_rssi_bcn(phl_info);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	do {
117*4882a593Smuzhiyun 		if (*rssi_bcn_min == 0 || *rssi_bcn_min == 0xFF) {
118*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): (criteria = %d, cur = %d) criteria invalid, set criteria to cur\n",
119*4882a593Smuzhiyun 					__func__, *rssi_bcn_min, cur_rssi_bcn_min);
120*4882a593Smuzhiyun 			*rssi_bcn_min = cur_rssi_bcn_min; /* update with current_rssi */
121*4882a593Smuzhiyun 			break;
122*4882a593Smuzhiyun 		}
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 		if (DIFF(*rssi_bcn_min, cur_rssi_bcn_min) < ps_cap->lps_rssi_diff_threshold) {
125*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): (criteria = %d, cur = %d) RSSI diff < %d, do nothing\n",
126*4882a593Smuzhiyun 					__func__, *rssi_bcn_min, cur_rssi_bcn_min, ps_cap->lps_rssi_diff_threshold);
127*4882a593Smuzhiyun 			break;
128*4882a593Smuzhiyun 		}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): leave ps and update criteria from %d to %d\n", __func__, *rssi_bcn_min, cur_rssi_bcn_min);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 		leave_ps = true;
133*4882a593Smuzhiyun 		*rssi_bcn_min = cur_rssi_bcn_min;
134*4882a593Smuzhiyun 	} while (0);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	return leave_ps;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun /**
140*4882a593Smuzhiyun  * determine leave lps or not
141*4882a593Smuzhiyun  * return true if beacon offset changed
142*4882a593Smuzhiyun  * @ps: see cmd_ps
143*4882a593Smuzhiyun  */
_chk_bcn_offset_changed(struct cmd_ps * ps)144*4882a593Smuzhiyun bool _chk_bcn_offset_changed(struct cmd_ps *ps)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	struct phl_info_t *phl_info = ps->phl_info;
147*4882a593Smuzhiyun 	u8 ridx = MAX_WIFI_ROLE_NUMBER;
148*4882a593Smuzhiyun 	struct rtw_wifi_role_t *wrole = NULL;
149*4882a593Smuzhiyun 	struct rtw_bcn_offset *b_ofst_i = NULL;
150*4882a593Smuzhiyun 	bool leave_ps = false;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	for (ridx = 0; ridx < MAX_WIFI_ROLE_NUMBER; ridx++) {
153*4882a593Smuzhiyun 		wrole = rtw_phl_get_wrole_by_ridx(phl_info->phl_com, ridx);
154*4882a593Smuzhiyun 		if (wrole == NULL)
155*4882a593Smuzhiyun 			continue;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 		if (rtw_phl_role_is_client_category(wrole) && wrole->mstate == MLME_LINKED) {
158*4882a593Smuzhiyun 			b_ofst_i = phl_get_sta_bcn_offset_info(phl_info, wrole);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 			if (b_ofst_i->conf_lvl >= CONF_LVL_MID &&
161*4882a593Smuzhiyun 				b_ofst_i->offset != b_ofst_i->cr_tbtt_shift) {
162*4882a593Smuzhiyun 				PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): update ridx(%d) bcn offset from %d to %d TU\n",
163*4882a593Smuzhiyun 							__func__, ridx, b_ofst_i->cr_tbtt_shift, b_ofst_i->offset);
164*4882a593Smuzhiyun 				leave_ps = true;
165*4882a593Smuzhiyun 				break;
166*4882a593Smuzhiyun 			}
167*4882a593Smuzhiyun 		}
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 	return leave_ps;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /**
173*4882a593Smuzhiyun  * check whether to leave/enter lps
174*4882a593Smuzhiyun  * return true if ps need to change to the target state
175*4882a593Smuzhiyun  * @ps: see cmd_ps
176*4882a593Smuzhiyun  * @mac_id: macid of corresponding sta
177*4882a593Smuzhiyun  * @cur_state: currently lps state
178*4882a593Smuzhiyun  * @target_state: the target ps state
179*4882a593Smuzhiyun  */
180*4882a593Smuzhiyun static bool
_lps_state_judge_changed(struct cmd_ps * ps,u16 macid,u8 cur_state,u8 target_state)181*4882a593Smuzhiyun _lps_state_judge_changed(struct cmd_ps *ps, u16 macid, u8 cur_state, u8 target_state)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	struct phl_info_t *phl_info = ps->phl_info;
184*4882a593Smuzhiyun 	struct rtw_ps_cap_t *ps_cap = _get_ps_cap(ps->phl_info);
185*4882a593Smuzhiyun 	struct rtw_stats *phl_stats = &phl_info->phl_com->phl_stats;
186*4882a593Smuzhiyun 	struct rtw_phl_stainfo_t *sta = NULL;
187*4882a593Smuzhiyun 	bool change_state = false;
188*4882a593Smuzhiyun 	u8 rssi = 0;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	sta = rtw_phl_get_stainfo_by_macid(phl_info, macid);
191*4882a593Smuzhiyun 	if (sta == NULL) {
192*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): cannot get sta of macid %d.\n", __func__, macid);
193*4882a593Smuzhiyun 		return false;
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	rssi = rtw_hal_get_sta_rssi(sta);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	if (target_state == PS_STATE_ENTERED) {
199*4882a593Smuzhiyun 		if (cur_state == PS_STATE_LEAVED || cur_state == PS_STATE_PROTO) {
200*4882a593Smuzhiyun 			if (rssi > ps_cap->lps_rssi_enter_threshold &&
201*4882a593Smuzhiyun 				phl_stats->tx_traffic.lvl == RTW_TFC_IDLE &&
202*4882a593Smuzhiyun 				phl_stats->rx_traffic.lvl == RTW_TFC_IDLE) {
203*4882a593Smuzhiyun 				change_state = true;
204*4882a593Smuzhiyun 			}
205*4882a593Smuzhiyun 		}
206*4882a593Smuzhiyun 	} else {
207*4882a593Smuzhiyun 		if (cur_state == PS_STATE_ENTERED || cur_state == PS_STATE_PROTO) {
208*4882a593Smuzhiyun 			if (_chk_rssi_diff_reach_thld(ps) ||
209*4882a593Smuzhiyun 				_chk_bcn_offset_changed(ps) ||
210*4882a593Smuzhiyun 				rssi < ps_cap->lps_rssi_leave_threshold ||
211*4882a593Smuzhiyun 				phl_stats->tx_traffic.lvl != RTW_TFC_IDLE ||
212*4882a593Smuzhiyun 				phl_stats->rx_traffic.lvl != RTW_TFC_IDLE) {
213*4882a593Smuzhiyun 				change_state = true;
214*4882a593Smuzhiyun 			}
215*4882a593Smuzhiyun 		}
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	if (change_state) {
219*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): state %s -> %s, Tx(%s), Rx(%s), RSSI(%d)\n",
220*4882a593Smuzhiyun 				  __func__, _ps_state_to_str(cur_state), _ps_state_to_str(target_state),
221*4882a593Smuzhiyun 				  phl_tfc_lvl_to_str(phl_stats->tx_traffic.lvl),
222*4882a593Smuzhiyun 				  phl_tfc_lvl_to_str(phl_stats->rx_traffic.lvl), rssi);
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	return change_state;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
_set_ps_rson(struct cmd_ps * ps,u8 enter,char * rson)228*4882a593Smuzhiyun static void _set_ps_rson(struct cmd_ps *ps, u8 enter, char *rson)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	if (enter) {
231*4882a593Smuzhiyun 		_os_mem_set(phl_to_drvpriv(ps->phl_info), ps->enter_rson, 0, MAX_CMD_PS_RSON_LENGTH);
232*4882a593Smuzhiyun 		_os_mem_cpy(phl_to_drvpriv(ps->phl_info), ps->enter_rson, rson, MAX_CMD_PS_RSON_LENGTH);
233*4882a593Smuzhiyun 	} else {
234*4882a593Smuzhiyun 		_os_mem_set(phl_to_drvpriv(ps->phl_info), ps->leave_rson, 0, MAX_CMD_PS_RSON_LENGTH);
235*4882a593Smuzhiyun 		_os_mem_cpy(phl_to_drvpriv(ps->phl_info), ps->leave_rson, rson, MAX_CMD_PS_RSON_LENGTH);
236*4882a593Smuzhiyun 	}
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun /**
240*4882a593Smuzhiyun  * Leave power saving
241*4882a593Smuzhiyun  * return RTW_PHL_STATUS_SUCCESS if leave ps ok
242*4882a593Smuzhiyun  * @ps: see cmd_ps
243*4882a593Smuzhiyun  * @leave_proto: whether to leave protocol
244*4882a593Smuzhiyun  * @rson: the reason of leaving power saving
245*4882a593Smuzhiyun  */
_leave_ps(struct cmd_ps * ps,bool leave_proto,char * rson)246*4882a593Smuzhiyun enum rtw_phl_status _leave_ps(struct cmd_ps *ps, bool leave_proto, char *rson)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	struct phl_info_t *phl_info = ps->phl_info;
249*4882a593Smuzhiyun 	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
250*4882a593Smuzhiyun 	struct ps_cfg cfg = {0};
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	if (ps->ps_state == PS_STATE_LEAVED) {
253*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): not in power saving.\n", __func__);
254*4882a593Smuzhiyun 		return RTW_PHL_STATUS_SUCCESS;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	cfg.cur_pwr_lvl = ps->cur_pwr_lvl;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): leave %s (macid %d).\n",
260*4882a593Smuzhiyun 			  __func__, phl_ps_ps_mode_to_str(ps->ps_mode), ps->macid);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	if (ps->ps_mode == PS_MODE_LPS) {
263*4882a593Smuzhiyun 		if (!leave_proto) {
264*4882a593Smuzhiyun 			if (ps->ps_state == PS_STATE_PROTO) {
265*4882a593Smuzhiyun 				PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): in lps protocal only.\n", __func__);
266*4882a593Smuzhiyun 				return RTW_PHL_STATUS_SUCCESS;
267*4882a593Smuzhiyun 			}
268*4882a593Smuzhiyun 			cfg.pwr_cfg = true;
269*4882a593Smuzhiyun 			cfg.proto_cfg = false;
270*4882a593Smuzhiyun 		} else {
271*4882a593Smuzhiyun 			if (ps->ps_state == PS_STATE_PROTO) {
272*4882a593Smuzhiyun 				cfg.pwr_cfg = false;
273*4882a593Smuzhiyun 				cfg.proto_cfg = true;
274*4882a593Smuzhiyun 			} else {
275*4882a593Smuzhiyun 				cfg.pwr_cfg = true;
276*4882a593Smuzhiyun 				cfg.proto_cfg = true;
277*4882a593Smuzhiyun 			}
278*4882a593Smuzhiyun 		}
279*4882a593Smuzhiyun 		cfg.macid = ps->macid;
280*4882a593Smuzhiyun 		cfg.token = &ps->null_token;
281*4882a593Smuzhiyun 		cfg.pwr_lvl = PS_PWR_LVL_PWRON;
282*4882a593Smuzhiyun 		cfg.ps_mode = ps->ps_mode;
283*4882a593Smuzhiyun 	} else if (ps->ps_mode == PS_MODE_IPS) {
284*4882a593Smuzhiyun 		cfg.macid = ps->macid;
285*4882a593Smuzhiyun 		cfg.pwr_lvl = PS_PWR_LVL_PWRON;
286*4882a593Smuzhiyun 		cfg.ps_mode = ps->ps_mode;
287*4882a593Smuzhiyun 	} else {
288*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS_CMD], %s(): unknown ps mode!\n", __func__);
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	_set_ps_rson(ps, false, rson);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	status = phl_ps_leave_ps(phl_info, &cfg);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (status == RTW_PHL_STATUS_SUCCESS) {
296*4882a593Smuzhiyun 		ps->cur_pwr_lvl = cfg.pwr_lvl;
297*4882a593Smuzhiyun 		if (ps->ps_mode == PS_MODE_LPS) {
298*4882a593Smuzhiyun 			ps->ps_mode = (leave_proto != true) ? PS_MODE_LPS : PS_MODE_NONE;
299*4882a593Smuzhiyun 			ps->ps_state = (leave_proto != true) ? PS_STATE_PROTO : PS_STATE_LEAVED;
300*4882a593Smuzhiyun 			ps->macid = (leave_proto != true) ? ps->macid : PS_MACID_NONE;
301*4882a593Smuzhiyun 		} else {
302*4882a593Smuzhiyun 			ps->ps_mode = PS_MODE_NONE;
303*4882a593Smuzhiyun 			ps->ps_state = PS_STATE_LEAVED;
304*4882a593Smuzhiyun 			ps->macid = PS_MACID_NONE;
305*4882a593Smuzhiyun 		}
306*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): macid %d leave ps success, reason(%s).\n", __func__, cfg.macid, rson);
307*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): ps mode(%s), pwr lvl(%s), ps state(%s)\n",
308*4882a593Smuzhiyun 				__func__, phl_ps_ps_mode_to_str(ps->ps_mode),
309*4882a593Smuzhiyun 				phl_ps_pwr_lvl_to_str(ps->cur_pwr_lvl), _ps_state_to_str(ps->ps_state));
310*4882a593Smuzhiyun 	} else {
311*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS_CMD], %s(): leave ps fail! reason(%s).\n", __func__, rson);
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	return status;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun /**
318*4882a593Smuzhiyun  * Enter power saving
319*4882a593Smuzhiyun  * return RTW_PHL_STATUS_SUCCESS if enter ps ok
320*4882a593Smuzhiyun  * @ps: see cmd_ps
321*4882a593Smuzhiyun  * @ps_mode: target ps mode to enter
322*4882a593Smuzhiyun  * @macid: target macid to enter lps
323*4882a593Smuzhiyun  * @rson: the reason of entering power saving
324*4882a593Smuzhiyun  */
_enter_ps(struct cmd_ps * ps,u8 ps_mode,u16 macid,char * rson)325*4882a593Smuzhiyun enum rtw_phl_status _enter_ps(struct cmd_ps *ps, u8 ps_mode, u16 macid, char *rson)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
328*4882a593Smuzhiyun 	struct ps_cfg cfg = {0};
329*4882a593Smuzhiyun 	struct rtw_ps_cap_t *ps_cap = _get_ps_cap(ps->phl_info);
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	if (ps->ps_state == PS_STATE_ENTERED) {
332*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): already in power saving.\n", __func__);
333*4882a593Smuzhiyun 		return RTW_PHL_STATUS_SUCCESS;
334*4882a593Smuzhiyun 	}
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	cfg.cur_pwr_lvl = ps->cur_pwr_lvl;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): enter %s (macid %d).\n",
339*4882a593Smuzhiyun 			  __func__, phl_ps_ps_mode_to_str(ps_mode), macid);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	if (ps_mode == PS_MODE_LPS) {
342*4882a593Smuzhiyun 		cfg.proto_cfg = (ps->ps_state == PS_STATE_PROTO) ? false : true;
343*4882a593Smuzhiyun 		cfg.pwr_cfg = true;
344*4882a593Smuzhiyun 		cfg.macid = macid;
345*4882a593Smuzhiyun 		cfg.token = &ps->null_token;
346*4882a593Smuzhiyun 		cfg.pwr_lvl = phl_ps_judge_pwr_lvl(ps_cap->lps_cap, ps_mode, true);
347*4882a593Smuzhiyun 		cfg.ps_mode = ps_mode;
348*4882a593Smuzhiyun 		cfg.awake_interval = ps_cap->lps_awake_interval;
349*4882a593Smuzhiyun 		cfg.listen_bcn_mode = ps_cap->lps_listen_bcn_mode;
350*4882a593Smuzhiyun 		cfg.smart_ps_mode = ps_cap->lps_smart_ps_mode;
351*4882a593Smuzhiyun 	} else if (ps_mode == PS_MODE_IPS) {
352*4882a593Smuzhiyun 		cfg.macid = macid;
353*4882a593Smuzhiyun 		if (macid == PS_MACID_NONE)
354*4882a593Smuzhiyun 			cfg.pwr_lvl = PS_PWR_LVL_PWROFF;
355*4882a593Smuzhiyun 		else
356*4882a593Smuzhiyun 			cfg.pwr_lvl = phl_ps_judge_pwr_lvl(ps_cap->ips_cap, ps_mode, true);
357*4882a593Smuzhiyun 		cfg.ps_mode = ps_mode;
358*4882a593Smuzhiyun 	} else {
359*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS_CMD], %s(): unknown ps mode!\n", __func__);
360*4882a593Smuzhiyun 	}
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	_set_ps_rson(ps, true, rson);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	status = phl_ps_enter_ps(ps->phl_info, &cfg);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	if (status == RTW_PHL_STATUS_SUCCESS) {
367*4882a593Smuzhiyun 		ps->cur_pwr_lvl = cfg.pwr_lvl;
368*4882a593Smuzhiyun 		ps->ps_mode = cfg.ps_mode;
369*4882a593Smuzhiyun 		ps->macid = cfg.macid;
370*4882a593Smuzhiyun 		ps->ps_state = PS_STATE_ENTERED;
371*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): macid %d enter ps success, reason(%s).\n", __func__, ps->macid, rson);
372*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): ps mode(%s), pwr lvl(%s), ps state(%s)\n",
373*4882a593Smuzhiyun 					__func__, phl_ps_ps_mode_to_str(ps->ps_mode),
374*4882a593Smuzhiyun 					phl_ps_pwr_lvl_to_str(ps->cur_pwr_lvl), _ps_state_to_str(ps->ps_state));
375*4882a593Smuzhiyun 	} else {
376*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS_CMD], %s(): enter ps fail! reason(%s).\n", __func__, rson);
377*4882a593Smuzhiyun 	}
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	return status;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun 
_pop_idle_req(struct cmd_ps * ps,struct pwr_req ** req)382*4882a593Smuzhiyun static bool _pop_idle_req(struct cmd_ps *ps, struct pwr_req **req)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	void *d = phl_to_drvpriv(ps->phl_info);
385*4882a593Smuzhiyun 	_os_list *new_req = NULL;
386*4882a593Smuzhiyun 	bool ret = false;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	(*req) = NULL;
389*4882a593Smuzhiyun 	if (pq_pop(d, &(ps->req_idle_q), &new_req, _first, _bh)) {
390*4882a593Smuzhiyun 		(*req) = (struct pwr_req *)new_req;
391*4882a593Smuzhiyun 		ret = true;
392*4882a593Smuzhiyun 	} else {
393*4882a593Smuzhiyun 		ret = false;
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): remaining idle req cnt %d.\n", __func__, ps->req_idle_q.cnt);
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	return ret;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun 
_push_idle_req(struct cmd_ps * ps,struct pwr_req * req)401*4882a593Smuzhiyun static void _push_idle_req(struct cmd_ps *ps, struct pwr_req *req)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	void *d = phl_to_drvpriv(ps->phl_info);
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	pq_push(d, &(ps->req_idle_q), &(req->list), _tail, _bh);
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): remaining idle req cnt %d.\n", __func__, ps->req_idle_q.cnt);
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun 
_pop_busy_req(struct cmd_ps * ps,struct pwr_req ** req)410*4882a593Smuzhiyun static bool _pop_busy_req(struct cmd_ps *ps, struct pwr_req **req)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun 	void *d = phl_to_drvpriv(ps->phl_info);
413*4882a593Smuzhiyun 	_os_list *new_req = NULL;
414*4882a593Smuzhiyun 	bool ret = false;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	(*req) = NULL;
417*4882a593Smuzhiyun 	if (pq_pop(d, &(ps->req_busy_q), &new_req, _tail, _bh)) {
418*4882a593Smuzhiyun 		(*req) = (struct pwr_req *)new_req;
419*4882a593Smuzhiyun 		ret = true;
420*4882a593Smuzhiyun 	} else {
421*4882a593Smuzhiyun 		ret = false;
422*4882a593Smuzhiyun 	}
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): current busy req cnt %d.\n", __func__, ps->req_busy_q.cnt);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	return ret;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
_push_busy_req(struct cmd_ps * ps,struct pwr_req * req)429*4882a593Smuzhiyun static void _push_busy_req(struct cmd_ps *ps, struct pwr_req *req)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun 	void *d = phl_to_drvpriv(ps->phl_info);
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	pq_push(d, &(ps->req_busy_q), &(req->list), _tail, _bh);
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): current busy req cnt %d.\n", __func__, ps->req_busy_q.cnt);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun 
_cancel_pwr_req(struct cmd_ps * ps,u16 evt_id)438*4882a593Smuzhiyun static void _cancel_pwr_req(struct cmd_ps *ps, u16 evt_id)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun 	struct pwr_req *req = NULL;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	if (!_pop_busy_req(ps, &req)) {
443*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): busy queue is empty.\n", __func__);
444*4882a593Smuzhiyun 		return;
445*4882a593Smuzhiyun 	}
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): evt_id %d\n", __func__, req->evt_id);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	if (req->evt_id != evt_id && MSG_EVT_PHY_IDLE != evt_id)
450*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): evt_id mismatch.\n", __func__);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	req->evt_id = MSG_EVT_NONE;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	_push_idle_req(ps, req);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun 
_add_pwr_req(struct cmd_ps * ps,u16 evt_id)457*4882a593Smuzhiyun static enum rtw_phl_status _add_pwr_req(struct cmd_ps *ps, u16 evt_id)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun 	enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
460*4882a593Smuzhiyun 	struct pwr_req *req = NULL;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	if (!_pop_idle_req(ps, &req)) {
463*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS_CMD], %s(): idle queue is empty.\n", __func__);
464*4882a593Smuzhiyun 		return RTW_PHL_STATUS_RESOURCE;
465*4882a593Smuzhiyun 	}
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	req->evt_id = evt_id;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): evt_id %d\n", __func__, evt_id);
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	_push_busy_req(ps, req);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	return status;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun 
_init_pwr_req_q(struct cmd_ps * ps)476*4882a593Smuzhiyun static void _init_pwr_req_q(struct cmd_ps *ps)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun 	void *d = phl_to_drvpriv(ps->phl_info);
479*4882a593Smuzhiyun 	u8 i = 0;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	pq_init(d, &ps->req_busy_q);
482*4882a593Smuzhiyun 	pq_init(d, &ps->req_idle_q);
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	_os_mem_set(d, ps->req_pool, 0,
485*4882a593Smuzhiyun 		    sizeof(struct pwr_req) * MAX_PWE_REQ_NUM);
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	for (i = 0; i < MAX_PWE_REQ_NUM; i++) {
488*4882a593Smuzhiyun 		pq_push(d, &(ps->req_idle_q),
489*4882a593Smuzhiyun 			&(ps->req_pool[i].list), _tail, _bh);
490*4882a593Smuzhiyun 	}
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun 
_reset_pwr_req_q(struct cmd_ps * ps)493*4882a593Smuzhiyun static void _reset_pwr_req_q(struct cmd_ps *ps)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun 	void *d = phl_to_drvpriv(ps->phl_info);
496*4882a593Smuzhiyun 	u8 i = 0;
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	pq_reset(d, &ps->req_busy_q, _bh);
499*4882a593Smuzhiyun 	pq_reset(d, &ps->req_idle_q, _bh);
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	_os_mem_set(d, ps->req_pool, 0,
502*4882a593Smuzhiyun 		    sizeof(struct pwr_req) * MAX_PWE_REQ_NUM);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	for (i = 0; i < MAX_PWE_REQ_NUM; i++) {
505*4882a593Smuzhiyun 		pq_push(d, &(ps->req_idle_q),
506*4882a593Smuzhiyun 			&(ps->req_pool[i].list), _tail, _bh);
507*4882a593Smuzhiyun 	}
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun 
_deinit_pwr_req_q(struct cmd_ps * ps)510*4882a593Smuzhiyun static void _deinit_pwr_req_q(struct cmd_ps *ps)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	void *d = phl_to_drvpriv(ps->phl_info);
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	pq_deinit(d, &ps->req_busy_q);
515*4882a593Smuzhiyun 	pq_deinit(d, &ps->req_idle_q);
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun 
_init_ps_dflt_sw_cap(struct cmd_ps * ps)518*4882a593Smuzhiyun static void _init_ps_dflt_sw_cap(struct cmd_ps *ps)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun 	struct rtw_ps_cap_t *sw_cap = _get_ps_sw_cap(ps->phl_info);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	sw_cap->init_rf_state = RTW_RF_ON;
523*4882a593Smuzhiyun 	sw_cap->init_rt_stop_rson = PS_RT_RSON_NONE;
524*4882a593Smuzhiyun 	sw_cap->leave_fail_act = PS_LEAVE_FAIL_ACT_NONE;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	sw_cap->ips_en = PS_OP_MODE_DISABLED;
527*4882a593Smuzhiyun 	sw_cap->ips_cap = 0;
528*4882a593Smuzhiyun 	sw_cap->ips_wow_en = PS_OP_MODE_DISABLED;
529*4882a593Smuzhiyun 	sw_cap->ips_wow_cap = 0;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	sw_cap->lps_en = PS_OP_MODE_DISABLED;
532*4882a593Smuzhiyun 	sw_cap->lps_cap = 0;
533*4882a593Smuzhiyun 	sw_cap->lps_awake_interval = 0;
534*4882a593Smuzhiyun 	sw_cap->lps_listen_bcn_mode = RTW_LPS_RLBM_MIN;
535*4882a593Smuzhiyun 	sw_cap->lps_smart_ps_mode = RTW_LPS_TRX_PWR0;
536*4882a593Smuzhiyun 	sw_cap->lps_rssi_enter_threshold = 40;
537*4882a593Smuzhiyun 	sw_cap->lps_rssi_leave_threshold = 35;
538*4882a593Smuzhiyun 	sw_cap->lps_rssi_diff_threshold = 5;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	sw_cap->lps_wow_en = PS_OP_MODE_DISABLED;
541*4882a593Smuzhiyun 	sw_cap->lps_wow_cap = 0;
542*4882a593Smuzhiyun 	sw_cap->lps_wow_awake_interval = 0;
543*4882a593Smuzhiyun 	sw_cap->lps_wow_listen_bcn_mode = RTW_LPS_RLBM_MAX;
544*4882a593Smuzhiyun 	sw_cap->lps_wow_smart_ps_mode = RTW_LPS_TRX_PWR0;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun 
_cmd_ps_timer_cb(void * context)547*4882a593Smuzhiyun static void _cmd_ps_timer_cb(void *context)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun 	enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
550*4882a593Smuzhiyun 	struct cmd_ps *ps = (struct cmd_ps *)context;
551*4882a593Smuzhiyun 	struct phl_msg msg = {0};
552*4882a593Smuzhiyun 	struct phl_msg_attribute attr = {0};
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	PHL_DBG("[PS_CMD], %s(): \n", __func__);
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_POWER_MGNT);
557*4882a593Smuzhiyun 	SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_PS_PERIOD_CHK);
558*4882a593Smuzhiyun 	msg.band_idx = HW_BAND_0;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	pstatus = phl_disp_eng_send_msg(ps->phl_info, &msg, &attr, NULL);
561*4882a593Smuzhiyun 	if (pstatus != RTW_PHL_STATUS_SUCCESS) {
562*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS_CMD], %s(): fail to send MSG_EVT_PS_PERIOD_CHK.\n", __func__);
563*4882a593Smuzhiyun 	}
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun 
_ps_common_info_init(struct phl_info_t * phl_info)566*4882a593Smuzhiyun static void _ps_common_info_init(struct phl_info_t *phl_info)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun 	struct phl_ps_info *ps_info = &phl_info->ps_info;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	if (!ps_info->init) {
571*4882a593Smuzhiyun 		PHL_INFO("[PS_CMD], %s(): \n", __func__);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 		_os_atomic_set(phl_to_drvpriv(phl_info),
574*4882a593Smuzhiyun 					   &phl_info->ps_info.tx_ntfy,
575*4882a593Smuzhiyun 					   0);
576*4882a593Smuzhiyun 		ps_info->init = true;
577*4882a593Smuzhiyun 	}
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun 
_ps_common_info_deinit(struct phl_info_t * phl_info)580*4882a593Smuzhiyun static void _ps_common_info_deinit(struct phl_info_t *phl_info)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun 	struct phl_ps_info *ps_info = &phl_info->ps_info;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	if (ps_info->init) {
585*4882a593Smuzhiyun 		PHL_INFO("[PS_CMD], %s(): \n", __func__);
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 		_os_atomic_set(phl_to_drvpriv(phl_info),
588*4882a593Smuzhiyun 				   	   &phl_info->ps_info.tx_ntfy,
589*4882a593Smuzhiyun 					   0);
590*4882a593Smuzhiyun 		ps_info->init = false;
591*4882a593Smuzhiyun 	}
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun 
_ps_mdl_init(void * phl,void * dispr,void ** priv)594*4882a593Smuzhiyun static enum phl_mdl_ret_code _ps_mdl_init(void *phl, void *dispr, void **priv)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
597*4882a593Smuzhiyun 	struct cmd_ps *ps = NULL;
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], %s(): \n", __func__);
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	if (priv == NULL)
602*4882a593Smuzhiyun 		return MDL_RET_FAIL;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	(*priv) = NULL;
605*4882a593Smuzhiyun 	ps = (struct cmd_ps *)_os_mem_alloc(phl_to_drvpriv(phl_info),
606*4882a593Smuzhiyun 					       sizeof(struct cmd_ps));
607*4882a593Smuzhiyun 	if (ps == NULL) {
608*4882a593Smuzhiyun 		PHL_ERR("[PS_CMD], %s(): allocate cmd ps fail.\n", __func__);
609*4882a593Smuzhiyun 		return MDL_RET_FAIL;
610*4882a593Smuzhiyun 	}
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	_os_mem_set(phl_to_drvpriv(phl_info), ps, 0, sizeof(struct cmd_ps));
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	ps->phl_info = phl_info;
615*4882a593Smuzhiyun 	ps->dispr = dispr;
616*4882a593Smuzhiyun 	(*priv) = (void *)ps;
617*4882a593Smuzhiyun 	ps->cur_pwr_lvl = PS_PWR_LVL_PWRON;
618*4882a593Smuzhiyun 	ps->ps_state = PS_STATE_LEAVED;
619*4882a593Smuzhiyun 	ps->ps_mode = PS_MODE_NONE;
620*4882a593Smuzhiyun 	ps->rej_pwr_req = false;
621*4882a593Smuzhiyun 	ps->rt_stop_rson = PS_RT_RSON_NONE;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	_os_init_timer(phl_to_drvpriv(phl_info),
624*4882a593Smuzhiyun 	               &ps->ps_timer,
625*4882a593Smuzhiyun 	               _cmd_ps_timer_cb,
626*4882a593Smuzhiyun 	               ps,
627*4882a593Smuzhiyun 	               "phl_cmd_ps_timer");
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	_init_pwr_req_q(ps);
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	_init_ps_dflt_sw_cap(ps);
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	_ps_common_info_init(phl_info);
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	return MDL_RET_SUCCESS;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun 
_ps_mdl_deinit(void * dispr,void * priv)638*4882a593Smuzhiyun static void _ps_mdl_deinit(void *dispr, void *priv)
639*4882a593Smuzhiyun {
640*4882a593Smuzhiyun 	struct cmd_ps *ps = (struct cmd_ps *)priv;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], %s(): \n", __func__);
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	_os_release_timer(phl_to_drvpriv(ps->phl_info), &ps->ps_timer);
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	_deinit_pwr_req_q(ps);
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	_ps_common_info_deinit(ps->phl_info);
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	if (ps != NULL)
651*4882a593Smuzhiyun 		_os_mem_free(phl_to_drvpriv(ps->phl_info), ps, sizeof(struct cmd_ps));
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun 
_dump_ps_cap(struct cmd_ps * ps)654*4882a593Smuzhiyun static void _dump_ps_cap(struct cmd_ps *ps)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun 	struct rtw_ps_cap_t *ps_cap = NULL;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	ps_cap = _get_ps_cap(ps->phl_info);
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], %s(): \n", __func__);
661*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], init_rf_state: %d\n", ps_cap->init_rf_state);
662*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], init_rt_stop_rson: 0x%x\n", ps_cap->init_rt_stop_rson);
663*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], leave_fail_act: 0x%x\n", ps_cap->leave_fail_act);
664*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], ips_en: %d\n", ps_cap->ips_en);
665*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], ips_cap: %d\n", ps_cap->ips_cap);
666*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], ips_wow_en: %d\n", ps_cap->ips_wow_en);
667*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], ips_wow_cap: %d\n", ps_cap->ips_wow_cap);
668*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_en: %d\n", ps_cap->lps_en);
669*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_cap: %d\n", ps_cap->lps_cap);
670*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_awake_interval: %d\n", ps_cap->lps_awake_interval);
671*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_listen_bcn_mode: %d\n", ps_cap->lps_listen_bcn_mode);
672*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_smart_ps_mode: %d\n", ps_cap->lps_smart_ps_mode);
673*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_rssi_enter_threshold: %d\n", ps_cap->lps_rssi_enter_threshold);
674*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_rssi_leave_threshold: %d\n", ps_cap->lps_rssi_leave_threshold);
675*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_rssi_diff_threshold: %d\n", ps_cap->lps_rssi_diff_threshold);
676*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_wow_en: %d\n", ps_cap->lps_wow_en);
677*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_wow_cap: %d\n", ps_cap->lps_wow_cap);
678*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_wow_awake_interval: %d\n", ps_cap->lps_wow_awake_interval);
679*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_wow_listen_bcn_mode: %d\n", ps_cap->lps_wow_listen_bcn_mode);
680*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_wow_smart_ps_mode: %d\n", ps_cap->lps_wow_smart_ps_mode);
681*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], lps_pause_tx: %d\n", ps_cap->lps_pause_tx);
682*4882a593Smuzhiyun }
683*4882a593Smuzhiyun 
_leave_success_hdlr(struct cmd_ps * ps)684*4882a593Smuzhiyun static void _leave_success_hdlr(struct cmd_ps *ps)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun 	struct phl_data_ctl_t ctl = {0};
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	if (ps->stop_datapath) {
689*4882a593Smuzhiyun 		/* resume tx datapath */
690*4882a593Smuzhiyun 		ctl.id = PHL_MDL_POWER_MGNT;
691*4882a593Smuzhiyun 		ctl.cmd = PHL_DATA_CTL_SW_TX_RESUME;
692*4882a593Smuzhiyun 		phl_data_ctrler(ps->phl_info, &ctl, NULL);
693*4882a593Smuzhiyun 		ps->stop_datapath = false;
694*4882a593Smuzhiyun 	}
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun 
_leave_fail_hdlr(struct cmd_ps * ps)697*4882a593Smuzhiyun static void _leave_fail_hdlr(struct cmd_ps *ps)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun 	struct rtw_ps_cap_t *ps_cap = _get_ps_cap(ps->phl_info);
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	PHL_WARN("[PS_CMD], %s(): action 0x%x\n", __func__, ps_cap->leave_fail_act);
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	/* reject all power operation */
704*4882a593Smuzhiyun 	if (ps_cap->leave_fail_act & PS_LEAVE_FAIL_ACT_REJ_PWR)
705*4882a593Smuzhiyun 		ps->rej_pwr_req = true;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	/* L2 should be the last one */
708*4882a593Smuzhiyun 	if (ps_cap->leave_fail_act & PS_LEAVE_FAIL_ACT_L2)
709*4882a593Smuzhiyun 		phl_ser_send_msg(ps->phl_info, RTW_PHL_SER_L2_RESET);
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun 
_ps_mdl_start(void * dispr,void * priv)712*4882a593Smuzhiyun static enum phl_mdl_ret_code _ps_mdl_start(void *dispr, void *priv)
713*4882a593Smuzhiyun {
714*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_SUCCESS;
715*4882a593Smuzhiyun 	struct cmd_ps *ps = (struct cmd_ps *)priv;
716*4882a593Smuzhiyun 	struct rtw_ps_cap_t *ps_cap = _get_ps_cap(ps->phl_info);
717*4882a593Smuzhiyun 	u8 idx = 0;
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	ps->rt_stop_rson = ps_cap->init_rt_stop_rson;
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	_reset_pwr_req_q(ps);
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	phl_dispr_get_idx(dispr, &idx);
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	if (idx == 0) {
726*4882a593Smuzhiyun 		_dump_ps_cap(ps);
727*4882a593Smuzhiyun 		PHL_INFO("[PS_CMD], %s(): init rf state %d, reject pwr req %d\n",
728*4882a593Smuzhiyun 				__func__, ps_cap->init_rf_state, ps->rej_pwr_req);
729*4882a593Smuzhiyun 		if (ps_cap->init_rf_state == RTW_RF_OFF)
730*4882a593Smuzhiyun 			ps->rej_pwr_req = true;
731*4882a593Smuzhiyun 		if (ps->rej_pwr_req == true)
732*4882a593Smuzhiyun 			_enter_ps(ps, PS_MODE_IPS, PS_MACID_NONE, "mdl start with rf off");
733*4882a593Smuzhiyun 		_os_set_timer(phl_to_drvpriv(ps->phl_info), &ps->ps_timer, CMD_PS_TIMER_PERIOD);
734*4882a593Smuzhiyun 	}
735*4882a593Smuzhiyun 	return ret;
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun 
_ps_mdl_stop(void * dispr,void * priv)738*4882a593Smuzhiyun static enum phl_mdl_ret_code _ps_mdl_stop(void *dispr, void *priv)
739*4882a593Smuzhiyun {
740*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_SUCCESS;
741*4882a593Smuzhiyun 	struct cmd_ps *ps = (struct cmd_ps *)priv;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	if (ps->ps_state == PS_STATE_ENTERED) {
744*4882a593Smuzhiyun 		PHL_WARN("[PS_CMD], %s(): module stop in power saving!\n", __func__);
745*4882a593Smuzhiyun 		_leave_ps(ps, true, "mdl stop");
746*4882a593Smuzhiyun 	}
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	_os_cancel_timer(phl_to_drvpriv(ps->phl_info), &ps->ps_timer);
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], %s(): \n", __func__);
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	return ret;
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun 
_chk_role_all_no_link(struct cmd_ps * ps)755*4882a593Smuzhiyun static bool _chk_role_all_no_link(struct cmd_ps *ps)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun 	struct phl_info_t *phl_info = ps->phl_info;
758*4882a593Smuzhiyun 	u8 role_idx = 0;
759*4882a593Smuzhiyun 	bool ret = true;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	for (role_idx = 0; role_idx < MAX_WIFI_ROLE_NUMBER; role_idx++) {
762*4882a593Smuzhiyun 		if (phl_info->phl_com->wifi_roles[role_idx].active == false)
763*4882a593Smuzhiyun 			continue;
764*4882a593Smuzhiyun 		if (phl_info->phl_com->wifi_roles[role_idx].mstate != MLME_NO_LINK) {
765*4882a593Smuzhiyun 			ret = false;
766*4882a593Smuzhiyun 			break;
767*4882a593Smuzhiyun 		}
768*4882a593Smuzhiyun 	}
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	return ret;
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun 
_get_role_of_ps_permitted(struct cmd_ps * ps,u8 target_mode)773*4882a593Smuzhiyun static struct rtw_wifi_role_t *_get_role_of_ps_permitted(struct cmd_ps *ps, u8 target_mode)
774*4882a593Smuzhiyun {
775*4882a593Smuzhiyun 	struct phl_info_t *phl_info = ps->phl_info;
776*4882a593Smuzhiyun 	struct rtw_phl_com_t *phl_com = phl_info->phl_com;
777*4882a593Smuzhiyun 	u8 role_idx = 0;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	for (role_idx = 0; role_idx < MAX_WIFI_ROLE_NUMBER; role_idx++) {
780*4882a593Smuzhiyun 		if (phl_com->wifi_roles[role_idx].active == false)
781*4882a593Smuzhiyun 			continue;
782*4882a593Smuzhiyun 		if (phl_com->wifi_roles[role_idx].type == PHL_RTYPE_STATION) {
783*4882a593Smuzhiyun 			if (target_mode == PS_MODE_LPS &&
784*4882a593Smuzhiyun 				phl_com->wifi_roles[role_idx].mstate == MLME_LINKED)
785*4882a593Smuzhiyun 				return &(phl_com->wifi_roles[role_idx]);
786*4882a593Smuzhiyun 			else if (target_mode == PS_MODE_IPS &&
787*4882a593Smuzhiyun 					 phl_com->wifi_roles[role_idx].mstate == MLME_NO_LINK)
788*4882a593Smuzhiyun 				return &(phl_com->wifi_roles[role_idx]);
789*4882a593Smuzhiyun 		}
790*4882a593Smuzhiyun 	}
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	return NULL;
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun /**
796*4882a593Smuzhiyun  * go through all wifi roles and check whether input
797*4882a593Smuzhiyun  * ps mode desired is allowed with existing wroles
798*4882a593Smuzhiyun  * @ps: see cmd_ps
799*4882a593Smuzhiyun  * @target_mode: the desired ps mode (lps or ips)
800*4882a593Smuzhiyun  * @macid: target macid to enter lps
801*4882a593Smuzhiyun  */
_chk_wrole_with_ps_mode(struct cmd_ps * ps,u8 target_mode,u16 * macid)802*4882a593Smuzhiyun static bool _chk_wrole_with_ps_mode(struct cmd_ps *ps,
803*4882a593Smuzhiyun 		u8 target_mode, u16 *macid)
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun 	struct rtw_wifi_role_t *role = NULL;
806*4882a593Smuzhiyun 	bool ret = false;
807*4882a593Smuzhiyun 	struct rtw_phl_stainfo_t *sta = NULL;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	if (ps->mr_info.ap_active || ps->mr_info.gc_active) {
810*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): ap %d or gc %d, is active.\n", __func__,
811*4882a593Smuzhiyun 				ps->mr_info.ap_active, ps->mr_info.gc_active);
812*4882a593Smuzhiyun 		return false;
813*4882a593Smuzhiyun 	}
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	if (target_mode == PS_MODE_IPS) {
816*4882a593Smuzhiyun 		if (_chk_role_all_no_link(ps)) {
817*4882a593Smuzhiyun 			role = _get_role_of_ps_permitted(ps, PS_MODE_IPS);
818*4882a593Smuzhiyun 			if (role == NULL) {
819*4882a593Smuzhiyun 				PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): there is no suitable role to enter ips.\n", __func__);
820*4882a593Smuzhiyun 				return false;
821*4882a593Smuzhiyun 			}
822*4882a593Smuzhiyun 			sta = rtw_phl_get_stainfo_self(ps->phl_info, role);
823*4882a593Smuzhiyun 			if (sta == NULL) {
824*4882a593Smuzhiyun 				PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): cannot get sta info.\n", __func__);
825*4882a593Smuzhiyun 				return false;
826*4882a593Smuzhiyun 			}
827*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): role id to enter ips (%d).\n", __func__, role->id);
828*4882a593Smuzhiyun 			ps->sta = sta;
829*4882a593Smuzhiyun 			*macid = sta->macid;
830*4882a593Smuzhiyun 			ret = true;
831*4882a593Smuzhiyun 		}
832*4882a593Smuzhiyun 	} else if (target_mode == PS_MODE_LPS) {
833*4882a593Smuzhiyun 		role = _get_role_of_ps_permitted(ps, PS_MODE_LPS);
834*4882a593Smuzhiyun 		if (role == NULL) {
835*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): there is no suitable role to enter lps.\n", __func__);
836*4882a593Smuzhiyun 			return false;
837*4882a593Smuzhiyun 		}
838*4882a593Smuzhiyun 		sta = rtw_phl_get_stainfo_self(ps->phl_info, role);
839*4882a593Smuzhiyun 		if (sta == NULL) {
840*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): cannot get sta info.\n", __func__);
841*4882a593Smuzhiyun 			return false;
842*4882a593Smuzhiyun 		}
843*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): role id to enter lps (%d).\n", __func__, role->id);
844*4882a593Smuzhiyun 		ps->sta = sta;
845*4882a593Smuzhiyun 		*macid = sta->macid;
846*4882a593Smuzhiyun 		ret = true;
847*4882a593Smuzhiyun 	}
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): decide enter ps(%s), target mode(%s).\n",
850*4882a593Smuzhiyun 				__func__, (ret) ? "Yes" : "No", phl_ps_ps_mode_to_str(target_mode));
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	return ret;
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun 
_stop_datapath(struct cmd_ps * ps)855*4882a593Smuzhiyun static enum rtw_phl_status _stop_datapath(struct cmd_ps *ps)
856*4882a593Smuzhiyun {
857*4882a593Smuzhiyun 	struct phl_data_ctl_t ctl = {0};
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	/* stop tx datapath */
860*4882a593Smuzhiyun 	ctl.id = PHL_MDL_POWER_MGNT;
861*4882a593Smuzhiyun 	ctl.cmd = PHL_DATA_CTL_SW_TX_PAUSE;
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	if (phl_data_ctrler(ps->phl_info, &ctl, NULL) == RTW_PHL_STATUS_SUCCESS) {
864*4882a593Smuzhiyun 		ps->stop_datapath = true;
865*4882a593Smuzhiyun 		return RTW_PHL_STATUS_SUCCESS;
866*4882a593Smuzhiyun 	}
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 	return RTW_PHL_STATUS_FAILURE;
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun 
_is_datapath_active(struct cmd_ps * ps)871*4882a593Smuzhiyun static bool _is_datapath_active(struct cmd_ps *ps)
872*4882a593Smuzhiyun {
873*4882a593Smuzhiyun 	struct phl_info_t *phl_info = ps->phl_info;
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 	return (_os_atomic_read(phl_to_drvpriv(phl_info), &phl_info->phl_sw_tx_sts)
876*4882a593Smuzhiyun 			!= PHL_TX_STATUS_SW_PAUSE) ? true : false;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun /**
880*4882a593Smuzhiyun  * check current capability of power saving
881*4882a593Smuzhiyun  * return able to enter ps or not
882*4882a593Smuzhiyun  * @ps: see cmd_ps
883*4882a593Smuzhiyun  * @mode: the target ps mode to be check
884*4882a593Smuzhiyun  */
_chk_ps_cap(struct cmd_ps * ps,u8 mode)885*4882a593Smuzhiyun static bool _chk_ps_cap(struct cmd_ps *ps, u8 mode)
886*4882a593Smuzhiyun {
887*4882a593Smuzhiyun 	struct rtw_ps_cap_t *ps_cap = _get_ps_cap(ps->phl_info);
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): mode(%s), lps_en(%d), ips_en(%d), runtime stop reason(0x%x).\n",
890*4882a593Smuzhiyun 			__func__, phl_ps_ps_mode_to_str(mode), ps_cap->lps_en, ps_cap->ips_en, ps->rt_stop_rson);
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	switch (mode) {
893*4882a593Smuzhiyun 	case PS_MODE_LPS:
894*4882a593Smuzhiyun 		if (ps_cap->lps_en == PS_OP_MODE_DISABLED) {
895*4882a593Smuzhiyun 			return false;
896*4882a593Smuzhiyun 		} else if (ps_cap->lps_en == PS_OP_MODE_FORCE_ENABLED) {
897*4882a593Smuzhiyun 			/* force enable */
898*4882a593Smuzhiyun 			return true;
899*4882a593Smuzhiyun 		} else if (ps_cap->lps_en == PS_OP_MODE_AUTO) {
900*4882a593Smuzhiyun 			if (ps->rt_stop_rson == PS_RT_RSON_NONE)
901*4882a593Smuzhiyun 				return true;
902*4882a593Smuzhiyun 		}
903*4882a593Smuzhiyun 		break;
904*4882a593Smuzhiyun 	case PS_MODE_IPS:
905*4882a593Smuzhiyun 		if (ps_cap->ips_en == PS_OP_MODE_DISABLED) {
906*4882a593Smuzhiyun 			return false;
907*4882a593Smuzhiyun 		} else if (ps_cap->ips_en == PS_OP_MODE_FORCE_ENABLED) {
908*4882a593Smuzhiyun 			/* force enable */
909*4882a593Smuzhiyun 			return true;
910*4882a593Smuzhiyun 		} else if (ps_cap->ips_en == PS_OP_MODE_AUTO) {
911*4882a593Smuzhiyun 			if (ps->rt_stop_rson == PS_RT_RSON_NONE)
912*4882a593Smuzhiyun 				return true;
913*4882a593Smuzhiyun 		}
914*4882a593Smuzhiyun 		break;
915*4882a593Smuzhiyun 	default:
916*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): unknown ps mode.\n", __func__);
917*4882a593Smuzhiyun 		return false;
918*4882a593Smuzhiyun 	}
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	return false;
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun /**
924*4882a593Smuzhiyun  * check the condition of ips
925*4882a593Smuzhiyun  * return whether to enter ips or not
926*4882a593Smuzhiyun  * @ps: see cmd_ps
927*4882a593Smuzhiyun  */
_chk_ips_enter(struct cmd_ps * ps,u16 * macid)928*4882a593Smuzhiyun static bool _chk_ips_enter(struct cmd_ps *ps, u16 *macid)
929*4882a593Smuzhiyun {
930*4882a593Smuzhiyun 	if (TEST_STATUS_FLAG(ps->phl_info->phl_com->dev_state, RTW_DEV_RESUMING)) {
931*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): resume in progress.\n", __func__);
932*4882a593Smuzhiyun 		return false;
933*4882a593Smuzhiyun 	}
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun 	if (ps->rej_pwr_req == true) {
936*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): reject pwr req.\n", __func__);
937*4882a593Smuzhiyun 		return false;
938*4882a593Smuzhiyun 	}
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 	if (!_chk_ps_cap(ps, PS_MODE_IPS)) {
941*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): ips is not allowed.\n", __func__);
942*4882a593Smuzhiyun 		return false;
943*4882a593Smuzhiyun 	}
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun 	if (!phl_disp_eng_is_fg_empty(ps->phl_info, HW_BAND_0)) {
946*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): fg exist.\n", __func__);
947*4882a593Smuzhiyun 		return false;
948*4882a593Smuzhiyun 	}
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 	if (ps->req_busy_q.cnt) {
951*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): req q is not empty.\n", __func__);
952*4882a593Smuzhiyun 		return false;
953*4882a593Smuzhiyun 	}
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	if (ps->btc_req_pwr) {
956*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): btc req pwr.\n", __func__);
957*4882a593Smuzhiyun 		return false;
958*4882a593Smuzhiyun 	}
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	if (!_chk_wrole_with_ps_mode(ps, PS_MODE_IPS, macid)) {
961*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): no need to enter ips.\n", __func__);
962*4882a593Smuzhiyun 		return false;
963*4882a593Smuzhiyun 	}
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	return true;
966*4882a593Smuzhiyun }
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun /**
969*4882a593Smuzhiyun  * check the condition of lps
970*4882a593Smuzhiyun  * return whether to enter lps or not
971*4882a593Smuzhiyun  * @ps: see cmd_ps
972*4882a593Smuzhiyun  */
_chk_lps_enter(struct cmd_ps * ps,u16 * macid)973*4882a593Smuzhiyun static bool _chk_lps_enter(struct cmd_ps *ps, u16 *macid)
974*4882a593Smuzhiyun {
975*4882a593Smuzhiyun 	struct rtw_ps_cap_t *ps_cap = _get_ps_cap(ps->phl_info);
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 	/* check enter lps or not */
978*4882a593Smuzhiyun 
979*4882a593Smuzhiyun 	if (TEST_STATUS_FLAG(ps->phl_info->phl_com->dev_state, RTW_DEV_RESUMING)) {
980*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): resume in progress.\n", __func__);
981*4882a593Smuzhiyun 		return false;
982*4882a593Smuzhiyun 	}
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 	if (ps->rej_pwr_req == true) {
985*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): reject pwr req.\n", __func__);
986*4882a593Smuzhiyun 		return false;
987*4882a593Smuzhiyun 	}
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun 	/* check capability */
990*4882a593Smuzhiyun 	if (!_chk_ps_cap(ps, PS_MODE_LPS)) {
991*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): lps is not allowed.\n", __func__);
992*4882a593Smuzhiyun 		return false;
993*4882a593Smuzhiyun 	}
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 	/* check fg module */
996*4882a593Smuzhiyun 	if (!phl_disp_eng_is_fg_empty(ps->phl_info, HW_BAND_0)) {
997*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): fg exist.\n", __func__);
998*4882a593Smuzhiyun 		return false;
999*4882a593Smuzhiyun 	}
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	/* ref cnt */
1002*4882a593Smuzhiyun 	if (ps->req_busy_q.cnt) {
1003*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): req q is not empty.\n", __func__);
1004*4882a593Smuzhiyun 		return false;
1005*4882a593Smuzhiyun 	}
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	/* btc */
1008*4882a593Smuzhiyun 	if (ps->btc_req_pwr) {
1009*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): btc req pwr.\n", __func__);
1010*4882a593Smuzhiyun 		return false;
1011*4882a593Smuzhiyun 	}
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun 	if (ps->wdg_leave_ps == true) {
1014*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): just leave ps in watchdog prephase.\n", __func__);
1015*4882a593Smuzhiyun 		return false;
1016*4882a593Smuzhiyun 	}
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	/* check wifi role */
1019*4882a593Smuzhiyun 	if (!_chk_wrole_with_ps_mode(ps, PS_MODE_LPS, macid)) {
1020*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): no need to enter lps.\n", __func__);
1021*4882a593Smuzhiyun 		return false;
1022*4882a593Smuzhiyun 	}
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	/* lps */
1025*4882a593Smuzhiyun 	if (_lps_state_judge_changed(ps, *macid, ps->ps_state, PS_STATE_ENTERED)) {
1026*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): lps state changed.\n", __func__);
1027*4882a593Smuzhiyun 		/* check data path stop or not */
1028*4882a593Smuzhiyun 		if (ps_cap->lps_pause_tx) {
1029*4882a593Smuzhiyun 			if (!_is_datapath_active(ps)) {
1030*4882a593Smuzhiyun 				return true;
1031*4882a593Smuzhiyun 			} else {
1032*4882a593Smuzhiyun 				if (_stop_datapath(ps) == RTW_PHL_STATUS_SUCCESS)
1033*4882a593Smuzhiyun 					return true;
1034*4882a593Smuzhiyun 			}
1035*4882a593Smuzhiyun 		} else {
1036*4882a593Smuzhiyun 			return true;
1037*4882a593Smuzhiyun 		}
1038*4882a593Smuzhiyun 	}
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun 	return false;
1041*4882a593Smuzhiyun }
1042*4882a593Smuzhiyun 
_ps_watchdog_info_dump(struct cmd_ps * ps)1043*4882a593Smuzhiyun static void _ps_watchdog_info_dump(struct cmd_ps *ps)
1044*4882a593Smuzhiyun {
1045*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "========== CMD PS Info ========== \n");
1046*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "ps mode(%s), pwr lvl(%s), ps state(%s)\n",
1047*4882a593Smuzhiyun 			phl_ps_ps_mode_to_str(ps->ps_mode),
1048*4882a593Smuzhiyun 			phl_ps_pwr_lvl_to_str(ps->cur_pwr_lvl),
1049*4882a593Smuzhiyun 			_ps_state_to_str(ps->ps_state));
1050*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "req idle cnt(%d), req busy cnt(%d)\n",
1051*4882a593Smuzhiyun 			ps->req_idle_q.cnt, ps->req_busy_q.cnt);
1052*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "ap active(%s), gc active(%s)\n",
1053*4882a593Smuzhiyun 			(ps->mr_info.ap_active ? "yes" : "no"), (ps->mr_info.gc_active ? "yes" : "no"));
1054*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "reject all pwr req(%s), btc req pwr(%s), runtime stop reason(0x%x)\n",
1055*4882a593Smuzhiyun 			(ps->rej_pwr_req ? "yes" : "no"), (ps->btc_req_pwr ? "yes" : "no"), ps->rt_stop_rson);
1056*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "========== CMD PS Info ========== \n");
1057*4882a593Smuzhiyun }
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun /**
1060*4882a593Smuzhiyun  * pre-phase handler of watchdog
1061*4882a593Smuzhiyun  * will check whether to leave lps or not
1062*4882a593Smuzhiyun  * @ps: see cmd_ps
1063*4882a593Smuzhiyun  */
1064*4882a593Smuzhiyun static enum phl_mdl_ret_code
_ps_watchdog_pre_hdlr(struct cmd_ps * ps)1065*4882a593Smuzhiyun _ps_watchdog_pre_hdlr(struct cmd_ps *ps)
1066*4882a593Smuzhiyun {
1067*4882a593Smuzhiyun 	/* check leave lps or not */
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): pwr lvl(%s).\n", __func__, phl_ps_pwr_lvl_to_str(ps->cur_pwr_lvl));
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 	ps->wdg_leave_ps = false;
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun 	if (ps->rej_pwr_req == true) {
1074*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): reject pwr req.\n", __func__);
1075*4882a593Smuzhiyun 		return MDL_RET_CANNOT_IO;
1076*4882a593Smuzhiyun 	}
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 	if (ps->ps_mode == PS_MODE_IPS) {
1079*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): power off.\n", __func__);
1080*4882a593Smuzhiyun 		return MDL_RET_CANNOT_IO;
1081*4882a593Smuzhiyun 	}
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	if (ps->ps_state == PS_STATE_LEAVED) {
1084*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): not in power saving.\n", __func__);
1085*4882a593Smuzhiyun 		return MDL_RET_SUCCESS;
1086*4882a593Smuzhiyun 	} else {
1087*4882a593Smuzhiyun 		if (_lps_state_judge_changed(ps, ps->macid, ps->ps_state, PS_STATE_LEAVED)) {
1088*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): lps state changed.\n", __func__);
1089*4882a593Smuzhiyun 			if (_leave_ps(ps, true, "watchdog") == RTW_PHL_STATUS_SUCCESS) {
1090*4882a593Smuzhiyun 				ps->wdg_leave_ps = true;
1091*4882a593Smuzhiyun 				_leave_success_hdlr(ps);
1092*4882a593Smuzhiyun 				return MDL_RET_SUCCESS;
1093*4882a593Smuzhiyun 			} else {
1094*4882a593Smuzhiyun 				PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS_CMD], %s(): going to L2 reset!\n", __func__);
1095*4882a593Smuzhiyun 				_leave_fail_hdlr(ps);
1096*4882a593Smuzhiyun 				return MDL_RET_CANNOT_IO;
1097*4882a593Smuzhiyun 			}
1098*4882a593Smuzhiyun 		}
1099*4882a593Smuzhiyun 		if (ps->ps_state == PS_STATE_PROTO)
1100*4882a593Smuzhiyun 			return MDL_RET_SUCCESS;
1101*4882a593Smuzhiyun 		else
1102*4882a593Smuzhiyun 			return MDL_RET_CANNOT_IO;
1103*4882a593Smuzhiyun 	}
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun 
1106*4882a593Smuzhiyun /**
1107*4882a593Smuzhiyun  * post-phase handler of watchdog
1108*4882a593Smuzhiyun  * will check whether to enter lps or not
1109*4882a593Smuzhiyun  * @ps: see cmd_ps
1110*4882a593Smuzhiyun  */
1111*4882a593Smuzhiyun static enum phl_mdl_ret_code
_ps_watchdog_post_hdlr(struct cmd_ps * ps)1112*4882a593Smuzhiyun _ps_watchdog_post_hdlr(struct cmd_ps *ps)
1113*4882a593Smuzhiyun {
1114*4882a593Smuzhiyun 	u16 macid = PS_MACID_NONE;
1115*4882a593Smuzhiyun 
1116*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): pwr lvl(%s).\n", __func__, phl_ps_pwr_lvl_to_str(ps->cur_pwr_lvl));
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	if (_chk_lps_enter(ps, &macid))
1119*4882a593Smuzhiyun 		_enter_ps(ps, PS_MODE_LPS, macid, "watchdog");
1120*4882a593Smuzhiyun 	else if (_chk_ips_enter(ps, &macid))
1121*4882a593Smuzhiyun 		_enter_ps(ps, PS_MODE_IPS, macid, "watchdog");
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 	_ps_watchdog_info_dump(ps);
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun 	return MDL_RET_SUCCESS;
1126*4882a593Smuzhiyun }
1127*4882a593Smuzhiyun 
_phy_on_msg_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1128*4882a593Smuzhiyun static enum phl_mdl_ret_code _phy_on_msg_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_CANNOT_IO;
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun 	if (ps->rej_pwr_req == true) {
1133*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): reject pwr req.\n", __func__);
1134*4882a593Smuzhiyun 		return MDL_RET_CANNOT_IO;
1135*4882a593Smuzhiyun 	}
1136*4882a593Smuzhiyun 
1137*4882a593Smuzhiyun 	if (IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
1138*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], MSG_EVT_PHY_ON\n");
1139*4882a593Smuzhiyun 		if (_leave_ps(ps, true, "phy on") == RTW_PHL_STATUS_SUCCESS) {
1140*4882a593Smuzhiyun 			_add_pwr_req(ps, MSG_EVT_ID_FIELD(msg->msg_id));
1141*4882a593Smuzhiyun 			_leave_success_hdlr(ps);
1142*4882a593Smuzhiyun 			ret = MDL_RET_SUCCESS;
1143*4882a593Smuzhiyun 		} else {
1144*4882a593Smuzhiyun 			_leave_fail_hdlr(ps);
1145*4882a593Smuzhiyun 		}
1146*4882a593Smuzhiyun 	} else {
1147*4882a593Smuzhiyun 		ret = MDL_RET_SUCCESS;
1148*4882a593Smuzhiyun 	}
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	return ret;
1151*4882a593Smuzhiyun }
1152*4882a593Smuzhiyun 
_tx_pwr_req_msg_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1153*4882a593Smuzhiyun static enum phl_mdl_ret_code _tx_pwr_req_msg_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1154*4882a593Smuzhiyun {
1155*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_CANNOT_IO;
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun 	if (ps->rej_pwr_req == true) {
1158*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): reject pwr req.\n", __func__);
1159*4882a593Smuzhiyun 		return MDL_RET_CANNOT_IO;
1160*4882a593Smuzhiyun 	}
1161*4882a593Smuzhiyun 
1162*4882a593Smuzhiyun 	if (IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
1163*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], MSG_EVT_TRX_PWR_REQ\n");
1164*4882a593Smuzhiyun 		if (_leave_ps(ps, false, "tx req") == RTW_PHL_STATUS_SUCCESS) {
1165*4882a593Smuzhiyun 			_leave_success_hdlr(ps);
1166*4882a593Smuzhiyun 			ret = MDL_RET_SUCCESS;
1167*4882a593Smuzhiyun 		} else {
1168*4882a593Smuzhiyun 			_leave_fail_hdlr(ps);
1169*4882a593Smuzhiyun 		}
1170*4882a593Smuzhiyun 	} else {
1171*4882a593Smuzhiyun 		ret = MDL_RET_SUCCESS;
1172*4882a593Smuzhiyun 	}
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	return ret;
1175*4882a593Smuzhiyun }
1176*4882a593Smuzhiyun 
_phy_idle_msg_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1177*4882a593Smuzhiyun static enum phl_mdl_ret_code _phy_idle_msg_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1178*4882a593Smuzhiyun {
1179*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_CANNOT_IO;
1180*4882a593Smuzhiyun 	u16 macid = PS_MACID_NONE;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	if (!IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
1183*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], MSG_EVT_PHY_IDLE\n");
1184*4882a593Smuzhiyun 		_cancel_pwr_req(ps, MSG_EVT_ID_FIELD(msg->msg_id));
1185*4882a593Smuzhiyun 		/* check enter ips or not */
1186*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): try enter ips.\n", __func__);
1187*4882a593Smuzhiyun 		if (_chk_ips_enter(ps, &macid)) {
1188*4882a593Smuzhiyun 			_enter_ps(ps, PS_MODE_IPS, macid, "phy idle");
1189*4882a593Smuzhiyun 		}
1190*4882a593Smuzhiyun 		ret = MDL_RET_SUCCESS;
1191*4882a593Smuzhiyun 	} else {
1192*4882a593Smuzhiyun 		ret = MDL_RET_SUCCESS;
1193*4882a593Smuzhiyun 	}
1194*4882a593Smuzhiyun 
1195*4882a593Smuzhiyun 	return ret;
1196*4882a593Smuzhiyun }
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun /**
1199*4882a593Smuzhiyun  * pre-phase handler of msg
1200*4882a593Smuzhiyun  * leave ps and return corresponding status
1201*4882a593Smuzhiyun  * @ps: see cmd_ps
1202*4882a593Smuzhiyun  * @evt_id: evt id of msg
1203*4882a593Smuzhiyun  */
1204*4882a593Smuzhiyun static enum phl_mdl_ret_code
_ext_msg_pre_hdlr(struct cmd_ps * ps,u16 evt_id)1205*4882a593Smuzhiyun _ext_msg_pre_hdlr(struct cmd_ps *ps, u16 evt_id)
1206*4882a593Smuzhiyun {
1207*4882a593Smuzhiyun 	if (ps->rej_pwr_req == true) {
1208*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): reject pwr req.\n", __func__);
1209*4882a593Smuzhiyun 		return MDL_RET_CANNOT_IO;
1210*4882a593Smuzhiyun 	}
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 	/* power request */
1213*4882a593Smuzhiyun 	if (_leave_ps(ps, true, "ext msg req") == RTW_PHL_STATUS_SUCCESS) {
1214*4882a593Smuzhiyun 		_add_pwr_req(ps, evt_id);
1215*4882a593Smuzhiyun 		_leave_success_hdlr(ps);
1216*4882a593Smuzhiyun 		return MDL_RET_SUCCESS;
1217*4882a593Smuzhiyun 	} else {
1218*4882a593Smuzhiyun 		_leave_fail_hdlr(ps);
1219*4882a593Smuzhiyun 	}
1220*4882a593Smuzhiyun 
1221*4882a593Smuzhiyun 	return MDL_RET_CANNOT_IO;
1222*4882a593Smuzhiyun }
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun /**
1225*4882a593Smuzhiyun  * post-phase handler of msg
1226*4882a593Smuzhiyun  * cancel power req and chk enter ips or not
1227*4882a593Smuzhiyun  * @ps: see cmd_ps
1228*4882a593Smuzhiyun  * @evt_id: evt id of msg
1229*4882a593Smuzhiyun  */
1230*4882a593Smuzhiyun static enum phl_mdl_ret_code
_ext_msg_post_hdlr(struct cmd_ps * ps,u16 evt_id)1231*4882a593Smuzhiyun _ext_msg_post_hdlr(struct cmd_ps *ps, u16 evt_id)
1232*4882a593Smuzhiyun {
1233*4882a593Smuzhiyun 	u16 macid = PS_MACID_NONE;
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun 	/* cancel power request */
1236*4882a593Smuzhiyun 	_cancel_pwr_req(ps, evt_id);
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): try enter ips.\n", __func__);
1239*4882a593Smuzhiyun 	if (_chk_ips_enter(ps, &macid)) {
1240*4882a593Smuzhiyun 		_enter_ps(ps, PS_MODE_IPS, macid, "ext msg done");
1241*4882a593Smuzhiyun 	}
1242*4882a593Smuzhiyun 
1243*4882a593Smuzhiyun 	return MDL_RET_SUCCESS;
1244*4882a593Smuzhiyun }
1245*4882a593Smuzhiyun 
_ps_mr_info_upt(struct cmd_ps * ps,struct rtw_wifi_role_t * role)1246*4882a593Smuzhiyun static void _ps_mr_info_upt(struct cmd_ps *ps, struct rtw_wifi_role_t *role)
1247*4882a593Smuzhiyun {
1248*4882a593Smuzhiyun 	struct phl_info_t *phl_info = ps->phl_info;
1249*4882a593Smuzhiyun 	struct rtw_wifi_role_t *wr = NULL;
1250*4882a593Smuzhiyun 	u8 role_idx = 0;
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): id %d, type %d, mstate %d\n", __func__,
1253*4882a593Smuzhiyun 				role->id, role->type, role->mstate);
1254*4882a593Smuzhiyun 	#ifdef RTW_WKARD_PHL_NTFY_MEDIA_STS
1255*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): is_gc %d\n", __func__, role->is_gc);
1256*4882a593Smuzhiyun 	#endif
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun 	_os_mem_set(phl_to_drvpriv(phl_info), &ps->mr_info, 0, sizeof(struct _ps_mr_info));
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun 	for (role_idx = 0; role_idx < MAX_WIFI_ROLE_NUMBER; role_idx++) {
1261*4882a593Smuzhiyun 		wr = &(phl_info->phl_com->wifi_roles[role_idx]);
1262*4882a593Smuzhiyun 		if (wr->active == false)
1263*4882a593Smuzhiyun 			continue;
1264*4882a593Smuzhiyun 		#ifdef RTW_WKARD_PHL_NTFY_MEDIA_STS
1265*4882a593Smuzhiyun 		if (wr->type == PHL_RTYPE_STATION) {
1266*4882a593Smuzhiyun 			if(wr->is_gc == true && wr->mstate != MLME_NO_LINK)
1267*4882a593Smuzhiyun 				ps->mr_info.gc_active = true;
1268*4882a593Smuzhiyun 		}
1269*4882a593Smuzhiyun 		#endif
1270*4882a593Smuzhiyun 		if (wr->type == PHL_RTYPE_AP || wr->type == PHL_RTYPE_VAP ||
1271*4882a593Smuzhiyun 			wr->type == PHL_RTYPE_MESH ||wr->type == PHL_RTYPE_P2P_GO)
1272*4882a593Smuzhiyun 			ps->mr_info.ap_active = (wr->mstate == MLME_NO_LINK) ? false : true;
1273*4882a593Smuzhiyun 	}
1274*4882a593Smuzhiyun 
1275*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): gc_active %d, ap_active %d\n", __func__,
1276*4882a593Smuzhiyun 				ps->mr_info.gc_active, ps->mr_info.ap_active);
1277*4882a593Smuzhiyun }
1278*4882a593Smuzhiyun 
_is_ignored_mrc_evt(u16 evt_id)1279*4882a593Smuzhiyun static bool _is_ignored_mrc_evt(u16 evt_id)
1280*4882a593Smuzhiyun {
1281*4882a593Smuzhiyun 	return false;
1282*4882a593Smuzhiyun }
1283*4882a593Smuzhiyun 
1284*4882a593Smuzhiyun static enum phl_mdl_ret_code
_mrc_mdl_msg_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1285*4882a593Smuzhiyun _mrc_mdl_msg_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1286*4882a593Smuzhiyun {
1287*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_CANNOT_IO;
1288*4882a593Smuzhiyun 	struct rtw_role_cmd *rcmd = NULL;
1289*4882a593Smuzhiyun 	struct rtw_wifi_role_t *role = NULL;
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun 	if (_is_ignored_mrc_evt(MSG_EVT_ID_FIELD(msg->msg_id)))
1292*4882a593Smuzhiyun 		return MDL_RET_SUCCESS;
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	switch (MSG_EVT_ID_FIELD(msg->msg_id)) {
1295*4882a593Smuzhiyun 	case MSG_EVT_ROLE_NTFY:
1296*4882a593Smuzhiyun 		if (!IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
1297*4882a593Smuzhiyun 			if (msg->inbuf && (msg->inlen == sizeof(struct rtw_role_cmd))) {
1298*4882a593Smuzhiyun 				rcmd  = (struct rtw_role_cmd *)msg->inbuf;
1299*4882a593Smuzhiyun 				role = rcmd->wrole;
1300*4882a593Smuzhiyun 				_ps_mr_info_upt(ps, role);
1301*4882a593Smuzhiyun 			}
1302*4882a593Smuzhiyun 		}
1303*4882a593Smuzhiyun 		ret = MDL_RET_SUCCESS;
1304*4882a593Smuzhiyun 		break;
1305*4882a593Smuzhiyun 	default:
1306*4882a593Smuzhiyun 		if (ps->cur_pwr_lvl != PS_PWR_LVL_PWRON) {
1307*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): MDL_ID(%d)-EVT_ID(%d) get cannot I/O!\n", __func__,
1308*4882a593Smuzhiyun 		         MSG_MDL_ID_FIELD(msg->msg_id), MSG_EVT_ID_FIELD(msg->msg_id));
1309*4882a593Smuzhiyun 			ret = MDL_RET_CANNOT_IO;
1310*4882a593Smuzhiyun 		} else {
1311*4882a593Smuzhiyun 			ret = MDL_RET_SUCCESS;
1312*4882a593Smuzhiyun 		}
1313*4882a593Smuzhiyun 		break;
1314*4882a593Smuzhiyun 	}
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun 	return ret;
1317*4882a593Smuzhiyun }
1318*4882a593Smuzhiyun 
_is_ignored_ser_evt(u16 evt_id)1319*4882a593Smuzhiyun static bool _is_ignored_ser_evt(u16 evt_id)
1320*4882a593Smuzhiyun {
1321*4882a593Smuzhiyun 	if (MSG_EVT_SER_M9_L2_RESET != evt_id)
1322*4882a593Smuzhiyun 		return true;
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 	return false;
1325*4882a593Smuzhiyun }
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun static enum phl_mdl_ret_code
_ser_mdl_msg_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1328*4882a593Smuzhiyun _ser_mdl_msg_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1329*4882a593Smuzhiyun {
1330*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_CANNOT_IO;
1331*4882a593Smuzhiyun 
1332*4882a593Smuzhiyun 	if (_is_ignored_ser_evt(MSG_EVT_ID_FIELD(msg->msg_id)))
1333*4882a593Smuzhiyun 		return MDL_RET_SUCCESS;
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun 	switch (MSG_EVT_ID_FIELD(msg->msg_id)) {
1336*4882a593Smuzhiyun 	case MSG_EVT_SER_M9_L2_RESET:
1337*4882a593Smuzhiyun 		ret = MDL_RET_SUCCESS;
1338*4882a593Smuzhiyun 		break;
1339*4882a593Smuzhiyun 	default:
1340*4882a593Smuzhiyun 		if (ps->cur_pwr_lvl != PS_PWR_LVL_PWRON) {
1341*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): MDL_ID(%d)-EVT_ID(%d) get cannot I/O!\n",
1342*4882a593Smuzhiyun 			         __func__,
1343*4882a593Smuzhiyun 			         MSG_MDL_ID_FIELD(msg->msg_id),
1344*4882a593Smuzhiyun 			         MSG_EVT_ID_FIELD(msg->msg_id));
1345*4882a593Smuzhiyun 			ret = MDL_RET_CANNOT_IO;
1346*4882a593Smuzhiyun 		} else {
1347*4882a593Smuzhiyun 			ret = MDL_RET_SUCCESS;
1348*4882a593Smuzhiyun 		}
1349*4882a593Smuzhiyun 		break;
1350*4882a593Smuzhiyun 	}
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 	return ret;
1353*4882a593Smuzhiyun }
1354*4882a593Smuzhiyun 
_is_ignored_general_evt(u16 evt_id)1355*4882a593Smuzhiyun static bool _is_ignored_general_evt(u16 evt_id)
1356*4882a593Smuzhiyun {
1357*4882a593Smuzhiyun 	bool ret = false;
1358*4882a593Smuzhiyun 
1359*4882a593Smuzhiyun 	switch (evt_id) {
1360*4882a593Smuzhiyun 	case MSG_EVT_GET_USB_SW_ABILITY:
1361*4882a593Smuzhiyun 	case MSG_EVT_GET_USB_SPEED:
1362*4882a593Smuzhiyun 	case MSG_EVT_SW_WATCHDOG:
1363*4882a593Smuzhiyun 		ret = true;
1364*4882a593Smuzhiyun 		break;
1365*4882a593Smuzhiyun 	default:
1366*4882a593Smuzhiyun 		ret = false;
1367*4882a593Smuzhiyun 		break;
1368*4882a593Smuzhiyun 	}
1369*4882a593Smuzhiyun 
1370*4882a593Smuzhiyun 	return ret;
1371*4882a593Smuzhiyun }
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun #ifdef RTW_WKARD_LINUX_CMD_WKARD
1374*4882a593Smuzhiyun static enum phl_mdl_ret_code
_linux_cmd_wkard_hdlr(struct cmd_ps * ps)1375*4882a593Smuzhiyun _linux_cmd_wkard_hdlr(struct cmd_ps *ps)
1376*4882a593Smuzhiyun {
1377*4882a593Smuzhiyun 	if (ps->rej_pwr_req == true) {
1378*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): reject pwr req.\n", __func__);
1379*4882a593Smuzhiyun 		return MDL_RET_CANNOT_IO;
1380*4882a593Smuzhiyun 	}
1381*4882a593Smuzhiyun 
1382*4882a593Smuzhiyun 	/* power request */
1383*4882a593Smuzhiyun 	if (_leave_ps(ps, true, "linux cmd wkard") == RTW_PHL_STATUS_SUCCESS) {
1384*4882a593Smuzhiyun 		_leave_success_hdlr(ps);
1385*4882a593Smuzhiyun 		return MDL_RET_SUCCESS;
1386*4882a593Smuzhiyun 	} else {
1387*4882a593Smuzhiyun 		_leave_fail_hdlr(ps);
1388*4882a593Smuzhiyun 	}
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun 	return MDL_RET_CANNOT_IO;
1391*4882a593Smuzhiyun }
1392*4882a593Smuzhiyun #endif /* RTW_WKARD_LINUX_CMD_WKARD */
1393*4882a593Smuzhiyun 
1394*4882a593Smuzhiyun static enum phl_mdl_ret_code
_general_mdl_msg_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1395*4882a593Smuzhiyun _general_mdl_msg_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1396*4882a593Smuzhiyun {
1397*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_CANNOT_IO;
1398*4882a593Smuzhiyun 
1399*4882a593Smuzhiyun 	if (_is_ignored_general_evt(MSG_EVT_ID_FIELD(msg->msg_id)))
1400*4882a593Smuzhiyun 		return MDL_RET_SUCCESS;
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun 	switch (MSG_EVT_ID_FIELD(msg->msg_id)) {
1403*4882a593Smuzhiyun 	case MSG_EVT_CHG_OP_CH_DEF_START:
1404*4882a593Smuzhiyun 	case MSG_EVT_CHG_OP_CH_DEF_END:
1405*4882a593Smuzhiyun 	case MSG_EVT_SWCH_START:
1406*4882a593Smuzhiyun 	case MSG_EVT_PCIE_TRX_MIT:
1407*4882a593Smuzhiyun 	case MSG_EVT_FORCE_USB_SW:
1408*4882a593Smuzhiyun 	case MSG_EVT_GET_USB_SPEED:
1409*4882a593Smuzhiyun 	case MSG_EVT_GET_USB_SW_ABILITY:
1410*4882a593Smuzhiyun 	case MSG_EVT_CFG_AMPDU:
1411*4882a593Smuzhiyun 	case MSG_EVT_DFS_PAUSE_TX:
1412*4882a593Smuzhiyun 	case MSG_EVT_ROLE_RECOVER:
1413*4882a593Smuzhiyun 	case MSG_EVT_ROLE_SUSPEND:
1414*4882a593Smuzhiyun 	case MSG_EVT_HAL_SET_L2_LEAVE:
1415*4882a593Smuzhiyun 	case MSG_EVT_NOTIFY_HAL:
1416*4882a593Smuzhiyun 	case MSG_EVT_ISSUE_BCN:
1417*4882a593Smuzhiyun 	case MSG_EVT_STOP_BCN:
1418*4882a593Smuzhiyun 	case MSG_EVT_SEC_KEY:
1419*4882a593Smuzhiyun 	case MSG_EVT_ROLE_START:
1420*4882a593Smuzhiyun 	case MSG_EVT_ROLE_CHANGE:
1421*4882a593Smuzhiyun 	case MSG_EVT_ROLE_STOP:
1422*4882a593Smuzhiyun 	case MSG_EVT_STA_INFO_CTRL:
1423*4882a593Smuzhiyun 	case MSG_EVT_STA_MEDIA_STATUS_UPT:
1424*4882a593Smuzhiyun 	case MSG_EVT_CFG_CHINFO:
1425*4882a593Smuzhiyun 	case MSG_EVT_STA_CHG_STAINFO:
1426*4882a593Smuzhiyun #ifdef RTW_WKARD_LINUX_CMD_WKARD
1427*4882a593Smuzhiyun 	case MSG_EVT_LINUX_CMD_WRK_TRI_PS:
1428*4882a593Smuzhiyun #endif /* RTW_WKARD_LINUX_CMD_WKARD */
1429*4882a593Smuzhiyun 	case MSG_EVT_DBG_RX_DUMP:
1430*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): MDL_ID(%d)-EVT_ID(%d) in %s phase.\n", __func__,
1431*4882a593Smuzhiyun 			MSG_MDL_ID_FIELD(msg->msg_id), MSG_EVT_ID_FIELD(msg->msg_id),
1432*4882a593Smuzhiyun 			(IS_MSG_IN_PRE_PHASE(msg->msg_id) ? "pre-protocol" : "post-protocol"));
1433*4882a593Smuzhiyun 		if (IS_MSG_IN_PRE_PHASE(msg->msg_id))
1434*4882a593Smuzhiyun 			ret = _ext_msg_pre_hdlr(ps, MSG_EVT_ID_FIELD(msg->msg_id));
1435*4882a593Smuzhiyun 		else
1436*4882a593Smuzhiyun 			ret = _ext_msg_post_hdlr(ps, MSG_EVT_ID_FIELD(msg->msg_id));
1437*4882a593Smuzhiyun 		break;
1438*4882a593Smuzhiyun #ifdef RTW_WKARD_LINUX_CMD_WKARD
1439*4882a593Smuzhiyun 	case MSG_EVT_LINUX_CMD_WRK:
1440*4882a593Smuzhiyun 		if (IS_MSG_IN_PRE_PHASE(msg->msg_id))
1441*4882a593Smuzhiyun 			ret = _linux_cmd_wkard_hdlr(ps);
1442*4882a593Smuzhiyun 		else
1443*4882a593Smuzhiyun 			ret = MDL_RET_SUCCESS;
1444*4882a593Smuzhiyun 		break;
1445*4882a593Smuzhiyun #endif /* RTW_WKARD_LINUX_CMD_WKARD */
1446*4882a593Smuzhiyun 	case MSG_EVT_HW_WATCHDOG:
1447*4882a593Smuzhiyun 		if (IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
1448*4882a593Smuzhiyun 			ret = _ps_watchdog_pre_hdlr(ps);
1449*4882a593Smuzhiyun 			if (ret == MDL_RET_SUCCESS) {
1450*4882a593Smuzhiyun 				ps->rssi_bcn_min = phl_get_min_rssi_bcn(ps->phl_info);
1451*4882a593Smuzhiyun 				PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): update rssi_bcn_min to %d\n", __func__, ps->rssi_bcn_min);
1452*4882a593Smuzhiyun 			}
1453*4882a593Smuzhiyun 		} else {
1454*4882a593Smuzhiyun 			ret = _ps_watchdog_post_hdlr(ps);
1455*4882a593Smuzhiyun 		}
1456*4882a593Smuzhiyun 		break;
1457*4882a593Smuzhiyun 	case MSG_EVT_RF_ON:
1458*4882a593Smuzhiyun 		if (!IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
1459*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], MSG_EVT_RF_ON\n");
1460*4882a593Smuzhiyun 			ps->rej_pwr_req = false;
1461*4882a593Smuzhiyun 		}
1462*4882a593Smuzhiyun 		ret = MDL_RET_SUCCESS;
1463*4882a593Smuzhiyun 		break;
1464*4882a593Smuzhiyun 	case MSG_EVT_RF_OFF:
1465*4882a593Smuzhiyun 		if (!IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
1466*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], MSG_EVT_RF_OFF\n");
1467*4882a593Smuzhiyun 			ps->rej_pwr_req = true;
1468*4882a593Smuzhiyun 			_enter_ps(ps, PS_MODE_IPS, PS_MACID_NONE, "msg rf off");
1469*4882a593Smuzhiyun 		}
1470*4882a593Smuzhiyun 		ret = MDL_RET_SUCCESS;
1471*4882a593Smuzhiyun 		break;
1472*4882a593Smuzhiyun 	case MSG_EVT_PHY_ON:
1473*4882a593Smuzhiyun 		ret = _phy_on_msg_hdlr(ps, msg);
1474*4882a593Smuzhiyun 		break;
1475*4882a593Smuzhiyun 	case MSG_EVT_PHY_IDLE:
1476*4882a593Smuzhiyun 		ret = _phy_idle_msg_hdlr(ps, msg);
1477*4882a593Smuzhiyun 		break;
1478*4882a593Smuzhiyun 	default:
1479*4882a593Smuzhiyun 		if (ps->cur_pwr_lvl != PS_PWR_LVL_PWRON) {
1480*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): MDL_ID(%d)-EVT_ID(%d) get cannot I/O!\n",
1481*4882a593Smuzhiyun 			         __func__,
1482*4882a593Smuzhiyun 			         MSG_MDL_ID_FIELD(msg->msg_id),
1483*4882a593Smuzhiyun 			         MSG_EVT_ID_FIELD(msg->msg_id));
1484*4882a593Smuzhiyun 			ret = MDL_RET_CANNOT_IO;
1485*4882a593Smuzhiyun 		} else {
1486*4882a593Smuzhiyun 			ret = MDL_RET_SUCCESS;
1487*4882a593Smuzhiyun 		}
1488*4882a593Smuzhiyun 		break;
1489*4882a593Smuzhiyun 	}
1490*4882a593Smuzhiyun 
1491*4882a593Smuzhiyun 	return ret;
1492*4882a593Smuzhiyun }
1493*4882a593Smuzhiyun 
_is_ignored_datapath_evt(u16 evt_id)1494*4882a593Smuzhiyun static bool _is_ignored_datapath_evt(u16 evt_id)
1495*4882a593Smuzhiyun {
1496*4882a593Smuzhiyun 	return false;
1497*4882a593Smuzhiyun }
1498*4882a593Smuzhiyun 
1499*4882a593Smuzhiyun static enum phl_mdl_ret_code
_datapath_mdl_msg_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1500*4882a593Smuzhiyun _datapath_mdl_msg_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1501*4882a593Smuzhiyun {
1502*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_CANNOT_IO;
1503*4882a593Smuzhiyun 
1504*4882a593Smuzhiyun 	if (_is_ignored_datapath_evt(MSG_EVT_ID_FIELD(msg->msg_id)))
1505*4882a593Smuzhiyun 		return MDL_RET_SUCCESS;
1506*4882a593Smuzhiyun 
1507*4882a593Smuzhiyun 	switch (MSG_EVT_ID_FIELD(msg->msg_id)) {
1508*4882a593Smuzhiyun 	case MSG_EVT_TRX_PWR_REQ:
1509*4882a593Smuzhiyun 		ret = _tx_pwr_req_msg_hdlr(ps, msg);
1510*4882a593Smuzhiyun 		break;
1511*4882a593Smuzhiyun 	default:
1512*4882a593Smuzhiyun 		if (ps->cur_pwr_lvl != PS_PWR_LVL_PWRON) {
1513*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): MDL_ID(%d)-EVT_ID(%d) get cannot I/O!\n",
1514*4882a593Smuzhiyun 			         __func__,
1515*4882a593Smuzhiyun 			         MSG_MDL_ID_FIELD(msg->msg_id),
1516*4882a593Smuzhiyun 			         MSG_EVT_ID_FIELD(msg->msg_id));
1517*4882a593Smuzhiyun 			ret = MDL_RET_CANNOT_IO;
1518*4882a593Smuzhiyun 		} else {
1519*4882a593Smuzhiyun 			ret = MDL_RET_SUCCESS;
1520*4882a593Smuzhiyun 		}
1521*4882a593Smuzhiyun 		break;
1522*4882a593Smuzhiyun 	}
1523*4882a593Smuzhiyun 
1524*4882a593Smuzhiyun 	return ret;
1525*4882a593Smuzhiyun }
1526*4882a593Smuzhiyun 
1527*4882a593Smuzhiyun /**
1528*4882a593Smuzhiyun  * bypass msg of specific module
1529*4882a593Smuzhiyun  * @msg: see phl_msg
1530*4882a593Smuzhiyun  */
_is_ignored_mdl(struct phl_msg * msg)1531*4882a593Smuzhiyun static bool _is_ignored_mdl(struct phl_msg *msg)
1532*4882a593Smuzhiyun {
1533*4882a593Smuzhiyun 	if (MSG_MDL_ID_FIELD(msg->msg_id) == PHL_MDL_BTC)
1534*4882a593Smuzhiyun 		return true;
1535*4882a593Smuzhiyun 	if (MSG_MDL_ID_FIELD(msg->msg_id) == PHL_MDL_LED)
1536*4882a593Smuzhiyun 		return true;
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 	return false;
1539*4882a593Smuzhiyun }
1540*4882a593Smuzhiyun 
1541*4882a593Smuzhiyun static enum phl_mdl_ret_code
_ps_mdl_hdl_external_evt(void * dispr,struct cmd_ps * ps,struct phl_msg * msg)1542*4882a593Smuzhiyun _ps_mdl_hdl_external_evt(void *dispr, struct cmd_ps *ps, struct phl_msg *msg)
1543*4882a593Smuzhiyun {
1544*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_CANNOT_IO;
1545*4882a593Smuzhiyun 
1546*4882a593Smuzhiyun 	if (_is_ignored_mdl(msg)) {
1547*4882a593Smuzhiyun 		/* PHL_INFO("[PS_CMD], %s(): ignore MDL_ID(%d)-EVT_ID(%d).\n", __func__,
1548*4882a593Smuzhiyun 		         MSG_MDL_ID_FIELD(msg->msg_id), MSG_EVT_ID_FIELD(msg->msg_id)); */
1549*4882a593Smuzhiyun 		return MDL_RET_SUCCESS;
1550*4882a593Smuzhiyun 	}
1551*4882a593Smuzhiyun 
1552*4882a593Smuzhiyun 	switch (MSG_MDL_ID_FIELD(msg->msg_id)) {
1553*4882a593Smuzhiyun 	case PHL_MDL_GENERAL:
1554*4882a593Smuzhiyun 		ret = _general_mdl_msg_hdlr(ps, msg);
1555*4882a593Smuzhiyun 		break;
1556*4882a593Smuzhiyun 	case PHL_MDL_MRC:
1557*4882a593Smuzhiyun 		ret = _mrc_mdl_msg_hdlr(ps, msg);
1558*4882a593Smuzhiyun 		break;
1559*4882a593Smuzhiyun 	case PHL_MDL_TX:
1560*4882a593Smuzhiyun 	case PHL_MDL_RX:
1561*4882a593Smuzhiyun 		ret = _datapath_mdl_msg_hdlr(ps, msg);
1562*4882a593Smuzhiyun 		break;
1563*4882a593Smuzhiyun 	case PHL_MDL_SER:
1564*4882a593Smuzhiyun 		ret = _ser_mdl_msg_hdlr(ps, msg);
1565*4882a593Smuzhiyun 		break;
1566*4882a593Smuzhiyun 	/* handle ohters mdl here */
1567*4882a593Smuzhiyun 	default:
1568*4882a593Smuzhiyun 		if (ps->cur_pwr_lvl != PS_PWR_LVL_PWRON) {
1569*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): MDL_ID(%d)-EVT_ID(%d) get cannot I/O!\n", __func__,
1570*4882a593Smuzhiyun 		         MSG_MDL_ID_FIELD(msg->msg_id), MSG_EVT_ID_FIELD(msg->msg_id));
1571*4882a593Smuzhiyun 			ret = MDL_RET_CANNOT_IO;
1572*4882a593Smuzhiyun 		} else {
1573*4882a593Smuzhiyun 			ret = MDL_RET_SUCCESS;
1574*4882a593Smuzhiyun 		}
1575*4882a593Smuzhiyun 		break;
1576*4882a593Smuzhiyun 	}
1577*4882a593Smuzhiyun 
1578*4882a593Smuzhiyun 	return ret;
1579*4882a593Smuzhiyun }
1580*4882a593Smuzhiyun 
_ps_cap_chg_msg_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1581*4882a593Smuzhiyun static enum phl_mdl_ret_code _ps_cap_chg_msg_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1582*4882a593Smuzhiyun {
1583*4882a593Smuzhiyun 	enum phl_ps_rt_rson  rt_rson = PS_RT_RSON_NONE;
1584*4882a593Smuzhiyun 	bool ps_allow = false;
1585*4882a593Smuzhiyun 	struct rt_ps *rt_ps_info= NULL;
1586*4882a593Smuzhiyun 	u16 macid = PS_MACID_NONE;
1587*4882a593Smuzhiyun 
1588*4882a593Smuzhiyun 	if (IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
1589*4882a593Smuzhiyun 		rt_ps_info = (struct rt_ps *)msg->inbuf;
1590*4882a593Smuzhiyun 		ps_allow = rt_ps_info->ps_allow;
1591*4882a593Smuzhiyun 		rt_rson = rt_ps_info->rt_rson;
1592*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): update -> ps_allow(%d), reason(%d).\n", __func__, ps_allow, rt_rson);
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun 		if (ps_allow) {
1595*4882a593Smuzhiyun 			if (TEST_STATUS_FLAG(ps->rt_stop_rson, rt_rson) == true)
1596*4882a593Smuzhiyun 				CLEAR_STATUS_FLAG(ps->rt_stop_rson, rt_rson);
1597*4882a593Smuzhiyun 			else
1598*4882a593Smuzhiyun 				return MDL_RET_SUCCESS;
1599*4882a593Smuzhiyun 		} else {
1600*4882a593Smuzhiyun 			if (TEST_STATUS_FLAG(ps->rt_stop_rson, rt_rson) == false)
1601*4882a593Smuzhiyun 				SET_STATUS_FLAG(ps->rt_stop_rson, rt_rson);
1602*4882a593Smuzhiyun 			else
1603*4882a593Smuzhiyun 				return MDL_RET_SUCCESS;
1604*4882a593Smuzhiyun 		}
1605*4882a593Smuzhiyun 
1606*4882a593Smuzhiyun 		if (ps->rej_pwr_req == true) {
1607*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): reject pwr req.\n", __func__);
1608*4882a593Smuzhiyun 			return MDL_RET_CANNOT_IO;
1609*4882a593Smuzhiyun 		}
1610*4882a593Smuzhiyun 
1611*4882a593Smuzhiyun 		if (ps->rt_stop_rson != PS_RT_RSON_NONE) {
1612*4882a593Smuzhiyun 			if (_leave_ps(ps, true, "cap chg") == RTW_PHL_STATUS_SUCCESS) {
1613*4882a593Smuzhiyun 				_leave_success_hdlr(ps);
1614*4882a593Smuzhiyun 				return MDL_RET_SUCCESS;
1615*4882a593Smuzhiyun 			} else {
1616*4882a593Smuzhiyun 				_leave_fail_hdlr(ps);
1617*4882a593Smuzhiyun 				return MDL_RET_CANNOT_IO;
1618*4882a593Smuzhiyun 			}
1619*4882a593Smuzhiyun 		}
1620*4882a593Smuzhiyun 	} else {
1621*4882a593Smuzhiyun 		if (ps->rt_stop_rson == PS_RT_RSON_NONE) {
1622*4882a593Smuzhiyun 			PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): try enter ips.\n", __func__);
1623*4882a593Smuzhiyun 			if (_chk_ips_enter(ps, &macid)) {
1624*4882a593Smuzhiyun 				_enter_ps(ps, PS_MODE_IPS, macid, "cap chg");
1625*4882a593Smuzhiyun 			}
1626*4882a593Smuzhiyun 		}
1627*4882a593Smuzhiyun 	}
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun 	return MDL_RET_SUCCESS;
1630*4882a593Smuzhiyun }
1631*4882a593Smuzhiyun 
_tx_pkt_ntfy_msg_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1632*4882a593Smuzhiyun static enum phl_mdl_ret_code _tx_pkt_ntfy_msg_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1633*4882a593Smuzhiyun {
1634*4882a593Smuzhiyun 	if (!IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
1635*4882a593Smuzhiyun 		PHL_DBG("[PS_CMD], %s(): rpwm with tx req.\n", __func__);
1636*4882a593Smuzhiyun 		/* rpwm with tx req */
1637*4882a593Smuzhiyun 		rtw_hal_ps_notify_wake(ps->phl_info->hal);
1638*4882a593Smuzhiyun 	}
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 	return MDL_RET_SUCCESS;
1641*4882a593Smuzhiyun }
1642*4882a593Smuzhiyun 
_ps_period_chk_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1643*4882a593Smuzhiyun static enum phl_mdl_ret_code _ps_period_chk_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1644*4882a593Smuzhiyun {
1645*4882a593Smuzhiyun 	u16 macid = PS_MACID_NONE;
1646*4882a593Smuzhiyun 
1647*4882a593Smuzhiyun 	if (IS_MSG_IN_PRE_PHASE(msg->msg_id))
1648*4882a593Smuzhiyun 		return MDL_RET_SUCCESS;
1649*4882a593Smuzhiyun 
1650*4882a593Smuzhiyun 	ps->wdg_leave_ps = false;
1651*4882a593Smuzhiyun 
1652*4882a593Smuzhiyun 	if (ps->ps_state != PS_STATE_ENTERED) {
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): \n", __func__);
1655*4882a593Smuzhiyun 		if (_chk_lps_enter(ps, &macid))
1656*4882a593Smuzhiyun 			_enter_ps(ps, PS_MODE_LPS, macid, "period chk");
1657*4882a593Smuzhiyun 	}
1658*4882a593Smuzhiyun 
1659*4882a593Smuzhiyun 	_os_set_timer(phl_to_drvpriv(ps->phl_info), &ps->ps_timer, CMD_PS_TIMER_PERIOD);
1660*4882a593Smuzhiyun 
1661*4882a593Smuzhiyun 	return MDL_RET_SUCCESS;
1662*4882a593Smuzhiyun }
1663*4882a593Smuzhiyun 
_ps_dbg_lps_msg_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1664*4882a593Smuzhiyun static enum phl_mdl_ret_code _ps_dbg_lps_msg_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1665*4882a593Smuzhiyun {
1666*4882a593Smuzhiyun 	u16 macid = PS_MACID_NONE;
1667*4882a593Smuzhiyun 	u16 evt_id = MSG_EVT_ID_FIELD(msg->msg_id);
1668*4882a593Smuzhiyun 
1669*4882a593Smuzhiyun 	if (evt_id == MSG_EVT_PS_DBG_LPS_ENTER) {
1670*4882a593Smuzhiyun 		if (!IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
1671*4882a593Smuzhiyun 			if (!_chk_wrole_with_ps_mode(ps, PS_MODE_LPS, &macid))
1672*4882a593Smuzhiyun 				return MDL_RET_SUCCESS;
1673*4882a593Smuzhiyun 			_enter_ps(ps, PS_MODE_LPS, macid, "dbg lps enter");
1674*4882a593Smuzhiyun 			ps->rej_pwr_req = true;
1675*4882a593Smuzhiyun 		}
1676*4882a593Smuzhiyun 	} else { /* MSG_EVT_PS_DBG_LPS_LEAVE */
1677*4882a593Smuzhiyun 		if (IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
1678*4882a593Smuzhiyun 			_leave_ps(ps, true, "dbg lps leave");
1679*4882a593Smuzhiyun 			ps->rej_pwr_req = false;
1680*4882a593Smuzhiyun 		}
1681*4882a593Smuzhiyun 	}
1682*4882a593Smuzhiyun 
1683*4882a593Smuzhiyun 	return MDL_RET_SUCCESS;
1684*4882a593Smuzhiyun }
1685*4882a593Smuzhiyun 
_ps_dbg_ips_msg_hdlr(struct cmd_ps * ps,struct phl_msg * msg)1686*4882a593Smuzhiyun static enum phl_mdl_ret_code _ps_dbg_ips_msg_hdlr(struct cmd_ps *ps, struct phl_msg *msg)
1687*4882a593Smuzhiyun {
1688*4882a593Smuzhiyun 	/* fw do not support ips currently */
1689*4882a593Smuzhiyun 	return MDL_RET_SUCCESS;
1690*4882a593Smuzhiyun }
1691*4882a593Smuzhiyun 
1692*4882a593Smuzhiyun static enum phl_mdl_ret_code
_ps_mdl_hdl_internal_evt(void * dispr,struct cmd_ps * ps,struct phl_msg * msg)1693*4882a593Smuzhiyun _ps_mdl_hdl_internal_evt(void *dispr, struct cmd_ps *ps, struct phl_msg *msg)
1694*4882a593Smuzhiyun {
1695*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_CANNOT_IO;
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun 	switch (MSG_EVT_ID_FIELD(msg->msg_id)) {
1698*4882a593Smuzhiyun 	case MSG_EVT_PHY_ON:
1699*4882a593Smuzhiyun 		ret = _phy_on_msg_hdlr(ps, msg);
1700*4882a593Smuzhiyun 		break;
1701*4882a593Smuzhiyun 	case MSG_EVT_PHY_IDLE:
1702*4882a593Smuzhiyun 		ret = _phy_idle_msg_hdlr(ps, msg);
1703*4882a593Smuzhiyun 		break;
1704*4882a593Smuzhiyun 	case MSG_EVT_PS_CAP_CHG:
1705*4882a593Smuzhiyun 		ret = _ps_cap_chg_msg_hdlr(ps, msg);
1706*4882a593Smuzhiyun 		break;
1707*4882a593Smuzhiyun 	case MSG_EVT_PS_PERIOD_CHK:
1708*4882a593Smuzhiyun 		ret = _ps_period_chk_hdlr(ps, msg);
1709*4882a593Smuzhiyun 		break;
1710*4882a593Smuzhiyun 	case MSG_EVT_PS_DBG_LPS_ENTER:
1711*4882a593Smuzhiyun 	case MSG_EVT_PS_DBG_LPS_LEAVE:
1712*4882a593Smuzhiyun 		ret = _ps_dbg_lps_msg_hdlr(ps, msg);
1713*4882a593Smuzhiyun 		break;
1714*4882a593Smuzhiyun 	case MSG_EVT_PS_DBG_IPS_ENTER:
1715*4882a593Smuzhiyun 	case MSG_EVT_PS_DBG_IPS_LEAVE:
1716*4882a593Smuzhiyun 		ret = _ps_dbg_ips_msg_hdlr(ps, msg);
1717*4882a593Smuzhiyun 		break;
1718*4882a593Smuzhiyun 	case MSG_EVT_TX_PKT_NTFY:
1719*4882a593Smuzhiyun 		ret = _tx_pkt_ntfy_msg_hdlr(ps, msg);
1720*4882a593Smuzhiyun 		break;
1721*4882a593Smuzhiyun 	default:
1722*4882a593Smuzhiyun 		ret = MDL_RET_CANNOT_IO;
1723*4882a593Smuzhiyun 		break;
1724*4882a593Smuzhiyun 	}
1725*4882a593Smuzhiyun 
1726*4882a593Smuzhiyun 	return ret;
1727*4882a593Smuzhiyun }
1728*4882a593Smuzhiyun 
1729*4882a593Smuzhiyun static enum phl_mdl_ret_code
_ps_mdl_msg_hdlr(void * dispr,void * priv,struct phl_msg * msg)1730*4882a593Smuzhiyun _ps_mdl_msg_hdlr(void *dispr, void *priv, struct phl_msg *msg)
1731*4882a593Smuzhiyun {
1732*4882a593Smuzhiyun 	enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
1733*4882a593Smuzhiyun 	struct cmd_ps *ps = (struct cmd_ps *)priv;
1734*4882a593Smuzhiyun 
1735*4882a593Smuzhiyun 	if (IS_MSG_FAIL(msg->msg_id)) {
1736*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): MDL_ID(%d)-EVT_ID(%d) fail.\n", __func__,
1737*4882a593Smuzhiyun 		         MSG_MDL_ID_FIELD(msg->msg_id), MSG_EVT_ID_FIELD(msg->msg_id));
1738*4882a593Smuzhiyun 		return MDL_RET_SUCCESS;
1739*4882a593Smuzhiyun 	}
1740*4882a593Smuzhiyun 
1741*4882a593Smuzhiyun 	switch (MSG_MDL_ID_FIELD(msg->msg_id)) {
1742*4882a593Smuzhiyun 		case PHL_MDL_POWER_MGNT:
1743*4882a593Smuzhiyun 			ret = _ps_mdl_hdl_internal_evt(dispr, ps, msg);
1744*4882a593Smuzhiyun 			break;
1745*4882a593Smuzhiyun 		default:
1746*4882a593Smuzhiyun 			ret = _ps_mdl_hdl_external_evt(dispr, ps, msg);
1747*4882a593Smuzhiyun 			break;
1748*4882a593Smuzhiyun 	}
1749*4882a593Smuzhiyun 
1750*4882a593Smuzhiyun 	return ret;
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun 
1753*4882a593Smuzhiyun static enum phl_mdl_ret_code
_ps_mdl_set_info(void * dispr,void * priv,struct phl_module_op_info * info)1754*4882a593Smuzhiyun _ps_mdl_set_info(void *dispr, void *priv, struct phl_module_op_info *info)
1755*4882a593Smuzhiyun {
1756*4882a593Smuzhiyun 	struct cmd_ps *ps = (struct cmd_ps *)priv;
1757*4882a593Smuzhiyun 
1758*4882a593Smuzhiyun 	switch (info->op_code) {
1759*4882a593Smuzhiyun 	case PS_MDL_OP_CANCEL_PWR_REQ:
1760*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): cancel pwr req, evt_id %d\n", __func__, *(u16 *)info->inbuf);
1761*4882a593Smuzhiyun 		if (ps->rej_pwr_req == false)
1762*4882a593Smuzhiyun 			_cancel_pwr_req(ps, *(u16 *)info->inbuf);
1763*4882a593Smuzhiyun 		break;
1764*4882a593Smuzhiyun 	case PS_MDL_OP_BTC_PWR_REQ:
1765*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): btc req pwr %d\n", __func__, *(bool *)info->inbuf);
1766*4882a593Smuzhiyun 		ps->btc_req_pwr = *(bool *)info->inbuf;
1767*4882a593Smuzhiyun 		break;
1768*4882a593Smuzhiyun 	}
1769*4882a593Smuzhiyun 
1770*4882a593Smuzhiyun 	return MDL_RET_SUCCESS;
1771*4882a593Smuzhiyun }
1772*4882a593Smuzhiyun 
1773*4882a593Smuzhiyun static enum phl_mdl_ret_code
_ps_mdl_query_info(void * dispr,void * priv,struct phl_module_op_info * info)1774*4882a593Smuzhiyun _ps_mdl_query_info(void *dispr, void *priv, struct phl_module_op_info *info)
1775*4882a593Smuzhiyun {
1776*4882a593Smuzhiyun 	struct cmd_ps *ps = (struct cmd_ps *)priv;
1777*4882a593Smuzhiyun 	u8 pwr_lvl = PS_PWR_LVL_PWROFF;
1778*4882a593Smuzhiyun 	struct phl_cmd_ps_basic_info *basic_info = NULL;
1779*4882a593Smuzhiyun 
1780*4882a593Smuzhiyun 	/* PHL_INFO("[PS_CMD], %s(): opcode %d.\n", __func__, info->op_code); */
1781*4882a593Smuzhiyun 
1782*4882a593Smuzhiyun 	switch (info->op_code) {
1783*4882a593Smuzhiyun 	case PS_MDL_OP_CUR_PWR_LVL:
1784*4882a593Smuzhiyun 		pwr_lvl = ps->cur_pwr_lvl;
1785*4882a593Smuzhiyun 		_os_mem_cpy(phl_to_drvpriv(ps->phl_info), (void *)info->inbuf,
1786*4882a593Smuzhiyun 					&pwr_lvl, sizeof(pwr_lvl));
1787*4882a593Smuzhiyun 		break;
1788*4882a593Smuzhiyun 	case PS_MDL_OP_BASIC_INFO:
1789*4882a593Smuzhiyun 		basic_info = (struct phl_cmd_ps_basic_info *)info->inbuf;
1790*4882a593Smuzhiyun 		basic_info->ps_mode = ps->ps_mode;
1791*4882a593Smuzhiyun 		basic_info->cur_pwr_lvl = ps->cur_pwr_lvl;
1792*4882a593Smuzhiyun 		basic_info->rej_pwr_req = ps->rej_pwr_req;
1793*4882a593Smuzhiyun 		basic_info->btc_req_pwr = ps->btc_req_pwr;
1794*4882a593Smuzhiyun 		basic_info->rt_stop_rson = ps->rt_stop_rson;
1795*4882a593Smuzhiyun 		basic_info->ap_active = ps->mr_info.ap_active;
1796*4882a593Smuzhiyun 		basic_info->gc_active = ps->mr_info.gc_active;
1797*4882a593Smuzhiyun 		basic_info->sta = ps->sta;
1798*4882a593Smuzhiyun 		/* enter/leave ps reason */
1799*4882a593Smuzhiyun 		_os_mem_set(phl_to_drvpriv(ps->phl_info), basic_info->enter_rson, 0, MAX_CMD_PS_RSON_LENGTH);
1800*4882a593Smuzhiyun 		_os_mem_cpy(phl_to_drvpriv(ps->phl_info), basic_info->enter_rson, ps->enter_rson, MAX_CMD_PS_RSON_LENGTH);
1801*4882a593Smuzhiyun 		_os_mem_set(phl_to_drvpriv(ps->phl_info), basic_info->leave_rson, 0, MAX_CMD_PS_RSON_LENGTH);
1802*4882a593Smuzhiyun 		_os_mem_cpy(phl_to_drvpriv(ps->phl_info), basic_info->leave_rson, ps->leave_rson, MAX_CMD_PS_RSON_LENGTH);
1803*4882a593Smuzhiyun 		break;
1804*4882a593Smuzhiyun 	}
1805*4882a593Smuzhiyun 
1806*4882a593Smuzhiyun 	return MDL_RET_SUCCESS;
1807*4882a593Smuzhiyun }
1808*4882a593Smuzhiyun 
phl_register_ps_module(struct phl_info_t * phl_info)1809*4882a593Smuzhiyun enum rtw_phl_status phl_register_ps_module(struct phl_info_t *phl_info)
1810*4882a593Smuzhiyun {
1811*4882a593Smuzhiyun 	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
1812*4882a593Smuzhiyun 	struct phl_cmd_dispatch_engine *disp_eng = &(phl_info->disp_eng);
1813*4882a593Smuzhiyun 	struct phl_bk_module_ops bk_ops = {0};
1814*4882a593Smuzhiyun 	u8 i = 0;
1815*4882a593Smuzhiyun 
1816*4882a593Smuzhiyun 	PHL_INFO("[PS_CMD], %s(): \n", __func__);
1817*4882a593Smuzhiyun 
1818*4882a593Smuzhiyun 	bk_ops.init = _ps_mdl_init;
1819*4882a593Smuzhiyun 	bk_ops.deinit = _ps_mdl_deinit;
1820*4882a593Smuzhiyun 	bk_ops.start = _ps_mdl_start;
1821*4882a593Smuzhiyun 	bk_ops.stop = _ps_mdl_stop;
1822*4882a593Smuzhiyun 	bk_ops.msg_hdlr = _ps_mdl_msg_hdlr;
1823*4882a593Smuzhiyun 	bk_ops.set_info = _ps_mdl_set_info;
1824*4882a593Smuzhiyun 	bk_ops.query_info = _ps_mdl_query_info;
1825*4882a593Smuzhiyun 
1826*4882a593Smuzhiyun 	for (i = 0; i < disp_eng->phy_num; i++) {
1827*4882a593Smuzhiyun 		phl_status = phl_disp_eng_register_module(phl_info, i,
1828*4882a593Smuzhiyun 						 PHL_MDL_POWER_MGNT, &bk_ops);
1829*4882a593Smuzhiyun 		if (phl_status != RTW_PHL_STATUS_SUCCESS) {
1830*4882a593Smuzhiyun 			PHL_ERR("register cmd PS module of phy%d failed.\n", i + 1);
1831*4882a593Smuzhiyun 			break;
1832*4882a593Smuzhiyun 		}
1833*4882a593Smuzhiyun 	}
1834*4882a593Smuzhiyun 
1835*4882a593Smuzhiyun 	return phl_status;
1836*4882a593Smuzhiyun }
1837*4882a593Smuzhiyun 
phl_ps_get_cur_pwr_lvl(struct phl_info_t * phl_info)1838*4882a593Smuzhiyun u8 phl_ps_get_cur_pwr_lvl(struct phl_info_t *phl_info)
1839*4882a593Smuzhiyun {
1840*4882a593Smuzhiyun 	struct phl_module_op_info op_info = {0};
1841*4882a593Smuzhiyun 	u8 pwr_lvl = PS_PWR_LVL_MAX;
1842*4882a593Smuzhiyun 
1843*4882a593Smuzhiyun 	op_info.op_code = PS_MDL_OP_CUR_PWR_LVL;
1844*4882a593Smuzhiyun 	op_info.inbuf = (u8 *)&pwr_lvl;
1845*4882a593Smuzhiyun 	op_info.inlen = sizeof(pwr_lvl);
1846*4882a593Smuzhiyun 
1847*4882a593Smuzhiyun 	phl_disp_eng_query_bk_module_info(phl_info, HW_BAND_0,
1848*4882a593Smuzhiyun 			PHL_MDL_POWER_MGNT, &op_info);
1849*4882a593Smuzhiyun 
1850*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS_CMD], %s(): pwr lvl(%s)\n", __func__, phl_ps_pwr_lvl_to_str(pwr_lvl));
1851*4882a593Smuzhiyun 
1852*4882a593Smuzhiyun 	return pwr_lvl;
1853*4882a593Smuzhiyun }
1854*4882a593Smuzhiyun 
phl_ps_is_datapath_allowed(struct phl_info_t * phl_info)1855*4882a593Smuzhiyun bool phl_ps_is_datapath_allowed(struct phl_info_t *phl_info)
1856*4882a593Smuzhiyun {
1857*4882a593Smuzhiyun 	struct phl_module_op_info op_info = {0};
1858*4882a593Smuzhiyun 	bool io_allowed = false;
1859*4882a593Smuzhiyun 	u8 pwr_lvl = PS_PWR_LVL_MAX;
1860*4882a593Smuzhiyun 	struct rtw_ps_cap_t *ps_cap = _get_ps_cap(phl_info);
1861*4882a593Smuzhiyun 
1862*4882a593Smuzhiyun 	if (!ps_cap->lps_pause_tx)
1863*4882a593Smuzhiyun 		return true;
1864*4882a593Smuzhiyun 
1865*4882a593Smuzhiyun 	op_info.op_code = PS_MDL_OP_CUR_PWR_LVL;
1866*4882a593Smuzhiyun 	op_info.inbuf = (u8 *)&pwr_lvl;
1867*4882a593Smuzhiyun 	op_info.inlen = sizeof(pwr_lvl);
1868*4882a593Smuzhiyun 
1869*4882a593Smuzhiyun 	phl_disp_eng_query_bk_module_info(phl_info, HW_BAND_0,
1870*4882a593Smuzhiyun 			PHL_MDL_POWER_MGNT, &op_info);
1871*4882a593Smuzhiyun 
1872*4882a593Smuzhiyun 	if (pwr_lvl == PS_PWR_LVL_PWRON)
1873*4882a593Smuzhiyun 		io_allowed = true;
1874*4882a593Smuzhiyun 
1875*4882a593Smuzhiyun 	return io_allowed;
1876*4882a593Smuzhiyun }
1877*4882a593Smuzhiyun 
_ps_tx_pkt_ntfy_done(void * priv,struct phl_msg * msg)1878*4882a593Smuzhiyun static void _ps_tx_pkt_ntfy_done(void *priv, struct phl_msg *msg)
1879*4882a593Smuzhiyun {
1880*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
1881*4882a593Smuzhiyun 
1882*4882a593Smuzhiyun 	PHL_DBG("[PS_CMD], %s(): reset ntfy\n", __func__);
1883*4882a593Smuzhiyun 
1884*4882a593Smuzhiyun 	_os_atomic_set(phl_to_drvpriv(phl_info),
1885*4882a593Smuzhiyun 				   &phl_info->ps_info.tx_ntfy,
1886*4882a593Smuzhiyun 				   0);
1887*4882a593Smuzhiyun }
1888*4882a593Smuzhiyun 
phl_ps_tx_pkt_ntfy(struct phl_info_t * phl_info)1889*4882a593Smuzhiyun void phl_ps_tx_pkt_ntfy(struct phl_info_t *phl_info)
1890*4882a593Smuzhiyun {
1891*4882a593Smuzhiyun 	struct phl_msg msg = {0};
1892*4882a593Smuzhiyun 	struct phl_msg_attribute attr = {0};
1893*4882a593Smuzhiyun 
1894*4882a593Smuzhiyun 	if (phl_ps_get_cur_pwr_lvl(phl_info) == PS_PWR_LVL_PWRON)
1895*4882a593Smuzhiyun 		return;
1896*4882a593Smuzhiyun 
1897*4882a593Smuzhiyun 	if (_os_atomic_read(phl_to_drvpriv(phl_info), &phl_info->ps_info.tx_ntfy)) {
1898*4882a593Smuzhiyun 		PHL_DBG("[PS_CMD], %s(): already ntfy\n", __func__);
1899*4882a593Smuzhiyun 		return;
1900*4882a593Smuzhiyun 	}
1901*4882a593Smuzhiyun 
1902*4882a593Smuzhiyun 	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_POWER_MGNT);
1903*4882a593Smuzhiyun 	SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_TX_PKT_NTFY);
1904*4882a593Smuzhiyun 	msg.band_idx = HW_BAND_0;
1905*4882a593Smuzhiyun 	attr.completion.completion = _ps_tx_pkt_ntfy_done;
1906*4882a593Smuzhiyun 	attr.completion.priv = phl_info;
1907*4882a593Smuzhiyun 
1908*4882a593Smuzhiyun 	_os_atomic_set(phl_to_drvpriv(phl_info),
1909*4882a593Smuzhiyun 				   &phl_info->ps_info.tx_ntfy,
1910*4882a593Smuzhiyun 				   1);
1911*4882a593Smuzhiyun 
1912*4882a593Smuzhiyun 	if (phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL) !=
1913*4882a593Smuzhiyun 				RTW_PHL_STATUS_SUCCESS) {
1914*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS_CMD], %s(): fail to send tx pkt notify.\n", __func__);
1915*4882a593Smuzhiyun 		_os_atomic_set(phl_to_drvpriv(phl_info),
1916*4882a593Smuzhiyun 				   	   &phl_info->ps_info.tx_ntfy,
1917*4882a593Smuzhiyun 				   	   0);
1918*4882a593Smuzhiyun 	}
1919*4882a593Smuzhiyun 
1920*4882a593Smuzhiyun 	return;
1921*4882a593Smuzhiyun }
1922*4882a593Smuzhiyun 
1923*4882a593Smuzhiyun 
_ps_set_rt_cap_done(void * priv,struct phl_msg * msg)1924*4882a593Smuzhiyun static void _ps_set_rt_cap_done(void *priv, struct phl_msg *msg)
1925*4882a593Smuzhiyun {
1926*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
1927*4882a593Smuzhiyun 
1928*4882a593Smuzhiyun 	if (msg->inbuf && msg->inlen) {
1929*4882a593Smuzhiyun 		_os_mem_free(phl_to_drvpriv(phl_info),
1930*4882a593Smuzhiyun 			msg->inbuf, msg->inlen);
1931*4882a593Smuzhiyun 	}
1932*4882a593Smuzhiyun 
1933*4882a593Smuzhiyun }
1934*4882a593Smuzhiyun 
rtw_phl_ps_set_rt_cap(void * phl,u8 band_idx,bool ps_allow,enum phl_ps_rt_rson rt_rson)1935*4882a593Smuzhiyun void rtw_phl_ps_set_rt_cap(void *phl, u8 band_idx, bool ps_allow, enum phl_ps_rt_rson rt_rson)
1936*4882a593Smuzhiyun {
1937*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
1938*4882a593Smuzhiyun 	struct phl_msg msg = {0};
1939*4882a593Smuzhiyun 	struct phl_msg_attribute attr = {0};
1940*4882a593Smuzhiyun 	struct rt_ps *ps_rt_info = NULL;
1941*4882a593Smuzhiyun 
1942*4882a593Smuzhiyun 	ps_rt_info = (struct rt_ps *)_os_mem_alloc(phl_to_drvpriv(phl_info), sizeof(struct rt_ps));
1943*4882a593Smuzhiyun 	if (ps_rt_info == NULL) {
1944*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS_CMD], %s(): fail to alloc ps_rt_info memory.\n", __func__);
1945*4882a593Smuzhiyun 		return;
1946*4882a593Smuzhiyun 	}
1947*4882a593Smuzhiyun 
1948*4882a593Smuzhiyun 	ps_rt_info->rt_rson = rt_rson;
1949*4882a593Smuzhiyun 	ps_rt_info->ps_allow = ps_allow;
1950*4882a593Smuzhiyun 
1951*4882a593Smuzhiyun 	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_POWER_MGNT);
1952*4882a593Smuzhiyun 	SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_PS_CAP_CHG);
1953*4882a593Smuzhiyun 	msg.band_idx = band_idx;
1954*4882a593Smuzhiyun 	msg.inbuf = (u8*)ps_rt_info;
1955*4882a593Smuzhiyun 	msg.inlen = sizeof(struct rt_ps);
1956*4882a593Smuzhiyun 	attr.completion.completion = _ps_set_rt_cap_done;
1957*4882a593Smuzhiyun 	attr.completion.priv = phl_info;
1958*4882a593Smuzhiyun 
1959*4882a593Smuzhiyun 	if (phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL) !=
1960*4882a593Smuzhiyun 				RTW_PHL_STATUS_SUCCESS) {
1961*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS_CMD], %s(): fail to notify batter change.\n", __func__);
1962*4882a593Smuzhiyun 		goto cmd_fail;
1963*4882a593Smuzhiyun 	}
1964*4882a593Smuzhiyun 
1965*4882a593Smuzhiyun 	return;
1966*4882a593Smuzhiyun 
1967*4882a593Smuzhiyun cmd_fail:
1968*4882a593Smuzhiyun 	_os_mem_free(phl_to_drvpriv(phl_info), ps_rt_info, sizeof(ps_rt_info));
1969*4882a593Smuzhiyun }
1970*4882a593Smuzhiyun 
phl_ps_dbg_set_ps(struct phl_info_t * phl_info,u8 ps_mode,bool enter)1971*4882a593Smuzhiyun void phl_ps_dbg_set_ps(struct phl_info_t *phl_info, u8 ps_mode, bool enter)
1972*4882a593Smuzhiyun {
1973*4882a593Smuzhiyun 	struct phl_msg msg = {0};
1974*4882a593Smuzhiyun 	struct phl_msg_attribute attr = {0};
1975*4882a593Smuzhiyun 	u16 evt_id = 0;
1976*4882a593Smuzhiyun 
1977*4882a593Smuzhiyun 	if (ps_mode == PS_MODE_LPS) {
1978*4882a593Smuzhiyun 		evt_id = (enter ? MSG_EVT_PS_DBG_LPS_ENTER : MSG_EVT_PS_DBG_LPS_LEAVE);
1979*4882a593Smuzhiyun 	} else if (ps_mode == PS_MODE_IPS) {
1980*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS_CMD], %s(): dbg ips is not support now.\n", __func__);
1981*4882a593Smuzhiyun 		/* evt_id = (enter ? MSG_EVT_PS_DBG_IPS_ENTER : MSG_EVT_PS_DBG_IPS_LEAVE); */
1982*4882a593Smuzhiyun 	} else {
1983*4882a593Smuzhiyun 		return;
1984*4882a593Smuzhiyun 	}
1985*4882a593Smuzhiyun 
1986*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS_CMD], %s(): debug set %s %s\n", __func__,
1987*4882a593Smuzhiyun 			phl_ps_ps_mode_to_str(ps_mode), (enter ? "enter" : "leave"));
1988*4882a593Smuzhiyun 
1989*4882a593Smuzhiyun 	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_POWER_MGNT);
1990*4882a593Smuzhiyun 	SET_MSG_EVT_ID_FIELD(msg.msg_id, evt_id);
1991*4882a593Smuzhiyun 	msg.band_idx = HW_BAND_0;
1992*4882a593Smuzhiyun 
1993*4882a593Smuzhiyun 	if (phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL) !=
1994*4882a593Smuzhiyun 				RTW_PHL_STATUS_SUCCESS) {
1995*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS_CMD], %s(): fail to set dbg ps.\n", __func__);
1996*4882a593Smuzhiyun 	}
1997*4882a593Smuzhiyun 
1998*4882a593Smuzhiyun 	return;
1999*4882a593Smuzhiyun }
2000*4882a593Smuzhiyun 
2001*4882a593Smuzhiyun enum rtw_phl_status
rtw_phl_ps_set_rf_state(void * phl,u8 band_idx,enum rtw_rf_state rf_state)2002*4882a593Smuzhiyun rtw_phl_ps_set_rf_state(void *phl, u8 band_idx, enum rtw_rf_state rf_state)
2003*4882a593Smuzhiyun {
2004*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
2005*4882a593Smuzhiyun 	enum phl_msg_evt_id evt_id = (rf_state == RTW_RF_ON) ? MSG_EVT_RF_ON : MSG_EVT_RF_OFF;
2006*4882a593Smuzhiyun 
2007*4882a593Smuzhiyun 	phl_cmd_enqueue(phl_info, band_idx, evt_id, NULL, 0, NULL, PHL_CMD_WAIT, 0);
2008*4882a593Smuzhiyun 
2009*4882a593Smuzhiyun 	return RTW_PHL_STATUS_SUCCESS;
2010*4882a593Smuzhiyun }
2011*4882a593Smuzhiyun 
phl_ps_hal_pwr_req(struct rtw_phl_com_t * phl_com,u8 src,bool pwr_req)2012*4882a593Smuzhiyun enum rtw_phl_status phl_ps_hal_pwr_req(struct rtw_phl_com_t *phl_com, u8 src, bool pwr_req)
2013*4882a593Smuzhiyun {
2014*4882a593Smuzhiyun 	enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
2015*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)phl_com->phl_priv;
2016*4882a593Smuzhiyun 	struct phl_module_op_info op_info = {0};
2017*4882a593Smuzhiyun 
2018*4882a593Smuzhiyun 	if (src != HAL_BTC_PWR_REQ)
2019*4882a593Smuzhiyun 		return RTW_PHL_STATUS_FAILURE;
2020*4882a593Smuzhiyun 
2021*4882a593Smuzhiyun 	op_info.op_code = PS_MDL_OP_BTC_PWR_REQ;
2022*4882a593Smuzhiyun 	op_info.inbuf = (u8 *)&pwr_req;
2023*4882a593Smuzhiyun 	status = phl_disp_eng_set_bk_module_info(phl_info, HW_BAND_0,
2024*4882a593Smuzhiyun 				PHL_MDL_POWER_MGNT, &op_info);
2025*4882a593Smuzhiyun 
2026*4882a593Smuzhiyun 	return status;
2027*4882a593Smuzhiyun }
2028*4882a593Smuzhiyun #endif
2029