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