xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/phl/phl_watchdog.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * Copyright(c) 2019 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_WATCHDOG_C_
16*4882a593Smuzhiyun #include "phl_headers.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #ifdef CONFIG_FSM
_phl_datapath_watchdog(struct phl_info_t * phl_info)19*4882a593Smuzhiyun static void _phl_datapath_watchdog(struct phl_info_t *phl_info)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	phl_tx_watchdog(phl_info);
22*4882a593Smuzhiyun 	phl_rx_watchdog(phl_info);
23*4882a593Smuzhiyun 	phl_sta_trx_tfc_upd(phl_info);
24*4882a593Smuzhiyun }
25*4882a593Smuzhiyun 
rtw_phl_watchdog_callback(void * phl)26*4882a593Smuzhiyun void rtw_phl_watchdog_callback(void *phl)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
29*4882a593Smuzhiyun 	do {
30*4882a593Smuzhiyun 		_phl_datapath_watchdog(phl_info);
31*4882a593Smuzhiyun 		#ifdef CONFIG_PCI_HCI
32*4882a593Smuzhiyun 		#ifdef RTW_WKARD_DYNAMIC_LTR
33*4882a593Smuzhiyun 		phl_ltr_ctrl_watchdog(phl_info);
34*4882a593Smuzhiyun 		#endif
35*4882a593Smuzhiyun 		#ifdef PCIE_TRX_MIT_EN
36*4882a593Smuzhiyun 		phl_pcie_trx_mit_watchdog(phl_info);
37*4882a593Smuzhiyun 		#endif
38*4882a593Smuzhiyun 		#endif
39*4882a593Smuzhiyun 		phl_mr_watchdog(phl_info);
40*4882a593Smuzhiyun 		rtw_hal_watchdog(phl_info->hal);
41*4882a593Smuzhiyun 	} while (false);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun #endif
44*4882a593Smuzhiyun 
_phl_watchdog_sw(struct phl_info_t * phl)45*4882a593Smuzhiyun static void _phl_watchdog_sw(struct phl_info_t *phl)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	/* Only sw statistics or sw behavior or trigger FG cmd */
48*4882a593Smuzhiyun 	phl_tx_watchdog(phl);
49*4882a593Smuzhiyun 	phl_rx_watchdog(phl);
50*4882a593Smuzhiyun 	phl_sta_trx_tfc_upd(phl);
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
_phl_watchdog_hw(struct phl_info_t * phl)53*4882a593Smuzhiyun static void _phl_watchdog_hw(struct phl_info_t *phl)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	#ifdef CONFIG_PHL_THERMAL_PROTECT
56*4882a593Smuzhiyun 	phl_thermal_protect_watchdog(phl);
57*4882a593Smuzhiyun 	#endif
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	/* I/O, tx behavior, request power, ... */
60*4882a593Smuzhiyun 	#ifdef CONFIG_PCI_HCI
61*4882a593Smuzhiyun 	#ifdef RTW_WKARD_DYNAMIC_LTR
62*4882a593Smuzhiyun 	phl_ltr_ctrl_watchdog(phl);
63*4882a593Smuzhiyun 	#endif
64*4882a593Smuzhiyun 	#ifdef PCIE_TRX_MIT_EN
65*4882a593Smuzhiyun 	phl_pcie_trx_mit_watchdog(phl);
66*4882a593Smuzhiyun 	#endif
67*4882a593Smuzhiyun 	#endif
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	phl_mr_watchdog(phl);
70*4882a593Smuzhiyun 	rtw_hal_watchdog(phl->hal);
71*4882a593Smuzhiyun 	phl_bcn_watchdog(phl);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun #ifdef CONFIG_CMD_DISP
_phl_watchdog_post_action(struct phl_info_t * phl_info)75*4882a593Smuzhiyun static void _phl_watchdog_post_action(struct phl_info_t *phl_info)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun #ifdef CONFIG_POWER_SAVE
78*4882a593Smuzhiyun 	rtw_hal_ps_chk_hw_rf_state(phl_info->phl_com, phl_info->hal);
79*4882a593Smuzhiyun #endif /* CONFIG_POWER_SAVE */
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
_phl_trigger_next_watchdog(struct phl_info_t * phl_info)82*4882a593Smuzhiyun static void _phl_trigger_next_watchdog(struct phl_info_t *phl_info)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	struct phl_watchdog *wdog = &(phl_info->wdog);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	if (wdog->state == WD_STATE_STARTED)
87*4882a593Smuzhiyun 		_os_set_timer(phl_to_drvpriv(phl_info), &wdog->wdog_timer, wdog->period);
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
_phl_watchdog_hw_done(void * drv_priv,u8 * cmd,u32 cmd_len,enum rtw_phl_status status)90*4882a593Smuzhiyun static void _phl_watchdog_hw_done(void *drv_priv, u8 *cmd, u32 cmd_len, enum rtw_phl_status status)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)cmd;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	_phl_watchdog_post_action(phl_info);
95*4882a593Smuzhiyun 	_phl_trigger_next_watchdog(phl_info);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun static enum rtw_phl_status
_phl_watchdog_hw_cmd(struct phl_info_t * phl_info,enum phl_cmd_type cmd_type,u32 cmd_timeout)99*4882a593Smuzhiyun _phl_watchdog_hw_cmd(struct phl_info_t *phl_info,
100*4882a593Smuzhiyun                   enum phl_cmd_type cmd_type,
101*4882a593Smuzhiyun                   u32 cmd_timeout)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (cmd_type == PHL_CMD_DIRECTLY) {
106*4882a593Smuzhiyun 		phl_status = phl_watchdog_hw_cmd_hdl(phl_info, RTW_PHL_STATUS_SUCCESS);
107*4882a593Smuzhiyun 		goto _exit;
108*4882a593Smuzhiyun 	}
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	/* watchdog dont care hw_band */
111*4882a593Smuzhiyun 	phl_status = phl_cmd_enqueue(phl_info,
112*4882a593Smuzhiyun 	                             HW_BAND_0,
113*4882a593Smuzhiyun 	                             MSG_EVT_HW_WATCHDOG,
114*4882a593Smuzhiyun 	                             (u8 *)phl_info,
115*4882a593Smuzhiyun 	                             0,
116*4882a593Smuzhiyun 	                             _phl_watchdog_hw_done,
117*4882a593Smuzhiyun 	                             cmd_type,
118*4882a593Smuzhiyun 	                             cmd_timeout);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	if (is_cmd_failure(phl_status)) {
121*4882a593Smuzhiyun 		/* Send cmd success, but wait cmd fail*/
122*4882a593Smuzhiyun 	} else if (phl_status != RTW_PHL_STATUS_SUCCESS) {
123*4882a593Smuzhiyun 		/* Send cmd fail */
124*4882a593Smuzhiyun 		phl_status = RTW_PHL_STATUS_FAILURE;
125*4882a593Smuzhiyun 	}
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun _exit:
129*4882a593Smuzhiyun 	return phl_status;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun 
_phl_watchdog_sw_done(void * drv_priv,u8 * cmd,u32 cmd_len,enum rtw_phl_status status)132*4882a593Smuzhiyun static void _phl_watchdog_sw_done(void *drv_priv, u8 *cmd, u32 cmd_len, enum rtw_phl_status status)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)cmd;
135*4882a593Smuzhiyun 	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
136*4882a593Smuzhiyun 	bool set_timer = true;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	if (true == phl_disp_eng_is_fg_empty(phl_info, HW_BAND_MAX)) {
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 		/* send watchdog cmd to request privilege of I/O */
141*4882a593Smuzhiyun 		psts = _phl_watchdog_hw_cmd(phl_info, PHL_CMD_NO_WAIT, 0);
142*4882a593Smuzhiyun 		if (psts != RTW_PHL_STATUS_FAILURE)
143*4882a593Smuzhiyun 			set_timer = false;
144*4882a593Smuzhiyun 	} else {
145*4882a593Smuzhiyun 		PHL_TRACE(COMP_PHL_DBG, _PHL_DEBUG_, "%s: skip watchdog\n",
146*4882a593Smuzhiyun 		          __FUNCTION__);
147*4882a593Smuzhiyun 	}
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	if (set_timer)
150*4882a593Smuzhiyun 		_phl_trigger_next_watchdog(phl_info);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun static enum rtw_phl_status
_phl_watchdog_sw_cmd(struct phl_info_t * phl_info,enum phl_cmd_type cmd_type,u32 cmd_timeout)154*4882a593Smuzhiyun _phl_watchdog_sw_cmd(struct phl_info_t *phl_info,
155*4882a593Smuzhiyun                   enum phl_cmd_type cmd_type,
156*4882a593Smuzhiyun                   u32 cmd_timeout)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	if (cmd_type == PHL_CMD_DIRECTLY) {
161*4882a593Smuzhiyun 		phl_status = phl_watchdog_sw_cmd_hdl(phl_info, RTW_PHL_STATUS_SUCCESS);
162*4882a593Smuzhiyun 		goto _exit;
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/* watchdog dont care hw_band */
166*4882a593Smuzhiyun 	phl_status = phl_cmd_enqueue(phl_info,
167*4882a593Smuzhiyun 	                             HW_BAND_0,
168*4882a593Smuzhiyun 	                             MSG_EVT_SW_WATCHDOG,
169*4882a593Smuzhiyun 	                             (u8 *)phl_info,
170*4882a593Smuzhiyun 	                             0,
171*4882a593Smuzhiyun 	                             _phl_watchdog_sw_done,
172*4882a593Smuzhiyun 	                             cmd_type,
173*4882a593Smuzhiyun 	                             cmd_timeout);
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (is_cmd_failure(phl_status)) {
176*4882a593Smuzhiyun 		/* Send cmd success, but wait cmd fail*/
177*4882a593Smuzhiyun 	} else if (phl_status != RTW_PHL_STATUS_SUCCESS) {
178*4882a593Smuzhiyun 		/* Send cmd fail */
179*4882a593Smuzhiyun 		phl_status = RTW_PHL_STATUS_FAILURE;
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun _exit:
184*4882a593Smuzhiyun 	return phl_status;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun #endif
187*4882a593Smuzhiyun 
_phl_watchdog_timer_expired(void * context)188*4882a593Smuzhiyun static void _phl_watchdog_timer_expired(void *context)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun #ifdef CONFIG_CMD_DISP
191*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)context;
192*4882a593Smuzhiyun 	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
193*4882a593Smuzhiyun 	bool set_timer = true;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	/* phl sw watchdog */
196*4882a593Smuzhiyun 	_phl_watchdog_sw(phl_info);
197*4882a593Smuzhiyun 	psts = _phl_watchdog_sw_cmd(phl_info, PHL_CMD_NO_WAIT, 0);
198*4882a593Smuzhiyun 	if (psts != RTW_PHL_STATUS_FAILURE)
199*4882a593Smuzhiyun 		set_timer = false;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	if (set_timer)
202*4882a593Smuzhiyun 		_phl_trigger_next_watchdog(phl_info);
203*4882a593Smuzhiyun #else
204*4882a593Smuzhiyun 	PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Not support watchdog\n", __FUNCTION__);
205*4882a593Smuzhiyun #endif
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun enum rtw_phl_status
phl_watchdog_hw_cmd_hdl(struct phl_info_t * phl_info,enum rtw_phl_status psts)209*4882a593Smuzhiyun phl_watchdog_hw_cmd_hdl(struct phl_info_t *phl_info, enum rtw_phl_status psts)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	struct phl_watchdog *wdog = &(phl_info->wdog);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	if (false == is_cmd_failure(psts)) {
214*4882a593Smuzhiyun 		_phl_watchdog_hw(phl_info);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 		if (NULL != wdog->core_hw_wdog)
217*4882a593Smuzhiyun 			wdog->core_hw_wdog(phl_to_drvpriv(phl_info));
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	return RTW_PHL_STATUS_SUCCESS;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun enum rtw_phl_status
phl_watchdog_sw_cmd_hdl(struct phl_info_t * phl_info,enum rtw_phl_status psts)224*4882a593Smuzhiyun phl_watchdog_sw_cmd_hdl(struct phl_info_t *phl_info, enum rtw_phl_status psts)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	struct phl_watchdog *wdog = &(phl_info->wdog);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	if (false == is_cmd_failure(psts)) {
229*4882a593Smuzhiyun 		if (NULL != wdog->core_sw_wdog)
230*4882a593Smuzhiyun 			wdog->core_sw_wdog(phl_to_drvpriv(phl_info));
231*4882a593Smuzhiyun 	}
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	return RTW_PHL_STATUS_SUCCESS;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
rtw_phl_watchdog_init(void * phl,u16 period,void (* core_sw_wdog)(void * drv_priv),void (* core_hw_wdog)(void * drv_priv))236*4882a593Smuzhiyun void rtw_phl_watchdog_init(void *phl,
237*4882a593Smuzhiyun                            u16 period,
238*4882a593Smuzhiyun                            void (*core_sw_wdog)(void *drv_priv),
239*4882a593Smuzhiyun                            void (*core_hw_wdog)(void *drv_priv))
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
242*4882a593Smuzhiyun 	struct phl_watchdog *wdog = &(phl_info->wdog);
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	wdog->state = WD_STATE_INIT;
245*4882a593Smuzhiyun 	wdog->core_sw_wdog = core_sw_wdog;
246*4882a593Smuzhiyun 	wdog->core_hw_wdog = core_hw_wdog;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	if (period > 0)
249*4882a593Smuzhiyun 		wdog->period = period;
250*4882a593Smuzhiyun 	else
251*4882a593Smuzhiyun 		wdog->period = WDOG_PERIOD;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	_os_init_timer(phl_to_drvpriv(phl_info),
254*4882a593Smuzhiyun 	               &wdog->wdog_timer,
255*4882a593Smuzhiyun 	               _phl_watchdog_timer_expired,
256*4882a593Smuzhiyun 	               phl,
257*4882a593Smuzhiyun 	               "phl_watchdog_timer");
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
rtw_phl_watchdog_deinit(void * phl)260*4882a593Smuzhiyun void rtw_phl_watchdog_deinit(void *phl)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
263*4882a593Smuzhiyun 	struct phl_watchdog *wdog = &(phl_info->wdog);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	_os_release_timer(phl_to_drvpriv(phl_info), &wdog->wdog_timer);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
rtw_phl_watchdog_start(void * phl)268*4882a593Smuzhiyun void rtw_phl_watchdog_start(void *phl)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
271*4882a593Smuzhiyun 	struct phl_watchdog *wdog = &(phl_info->wdog);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	wdog->state = WD_STATE_STARTED;
274*4882a593Smuzhiyun 	_phl_trigger_next_watchdog(phl_info);
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
rtw_phl_watchdog_stop(void * phl)277*4882a593Smuzhiyun void rtw_phl_watchdog_stop(void *phl)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
280*4882a593Smuzhiyun 	struct phl_watchdog *wdog = &(phl_info->wdog);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	PHL_INFO("%s\n", __func__);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	wdog->state = WD_STATE_STOP;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	_os_cancel_timer(phl_to_drvpriv(phl_info), &wdog->wdog_timer);
287*4882a593Smuzhiyun }
288