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