xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/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 (is_cmd_failure(phl_status)) {
176 		/* Send cmd success, but wait cmd fail*/
177 	} else if (phl_status != RTW_PHL_STATUS_SUCCESS) {
178 		/* Send cmd fail */
179 		phl_status = RTW_PHL_STATUS_FAILURE;
180 	}
181 
182 
183 _exit:
184 	return phl_status;
185 }
186 #endif
187 
_phl_watchdog_timer_expired(void * context)188 static void _phl_watchdog_timer_expired(void *context)
189 {
190 #ifdef CONFIG_CMD_DISP
191 	struct phl_info_t *phl_info = (struct phl_info_t *)context;
192 	enum rtw_phl_status psts = RTW_PHL_STATUS_FAILURE;
193 	bool set_timer = true;
194 
195 	/* phl sw watchdog */
196 	_phl_watchdog_sw(phl_info);
197 	psts = _phl_watchdog_sw_cmd(phl_info, PHL_CMD_NO_WAIT, 0);
198 	if (psts != RTW_PHL_STATUS_FAILURE)
199 		set_timer = false;
200 
201 	if (set_timer)
202 		_phl_trigger_next_watchdog(phl_info);
203 #else
204 	PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Not support watchdog\n", __FUNCTION__);
205 #endif
206 }
207 
208 enum rtw_phl_status
phl_watchdog_hw_cmd_hdl(struct phl_info_t * phl_info,enum rtw_phl_status psts)209 phl_watchdog_hw_cmd_hdl(struct phl_info_t *phl_info, enum rtw_phl_status psts)
210 {
211 	struct phl_watchdog *wdog = &(phl_info->wdog);
212 
213 	if (false == is_cmd_failure(psts)) {
214 		_phl_watchdog_hw(phl_info);
215 
216 		if (NULL != wdog->core_hw_wdog)
217 			wdog->core_hw_wdog(phl_to_drvpriv(phl_info));
218 	}
219 
220 	return RTW_PHL_STATUS_SUCCESS;
221 }
222 
223 enum rtw_phl_status
phl_watchdog_sw_cmd_hdl(struct phl_info_t * phl_info,enum rtw_phl_status psts)224 phl_watchdog_sw_cmd_hdl(struct phl_info_t *phl_info, enum rtw_phl_status psts)
225 {
226 	struct phl_watchdog *wdog = &(phl_info->wdog);
227 
228 	if (false == is_cmd_failure(psts)) {
229 		if (NULL != wdog->core_sw_wdog)
230 			wdog->core_sw_wdog(phl_to_drvpriv(phl_info));
231 	}
232 
233 	return RTW_PHL_STATUS_SUCCESS;
234 }
235 
rtw_phl_watchdog_init(void * phl,u16 period,void (* core_sw_wdog)(void * drv_priv),void (* core_hw_wdog)(void * drv_priv))236 void rtw_phl_watchdog_init(void *phl,
237                            u16 period,
238                            void (*core_sw_wdog)(void *drv_priv),
239                            void (*core_hw_wdog)(void *drv_priv))
240 {
241 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
242 	struct phl_watchdog *wdog = &(phl_info->wdog);
243 
244 	wdog->state = WD_STATE_INIT;
245 	wdog->core_sw_wdog = core_sw_wdog;
246 	wdog->core_hw_wdog = core_hw_wdog;
247 
248 	if (period > 0)
249 		wdog->period = period;
250 	else
251 		wdog->period = WDOG_PERIOD;
252 
253 	_os_init_timer(phl_to_drvpriv(phl_info),
254 	               &wdog->wdog_timer,
255 	               _phl_watchdog_timer_expired,
256 	               phl,
257 	               "phl_watchdog_timer");
258 }
259 
rtw_phl_watchdog_deinit(void * phl)260 void rtw_phl_watchdog_deinit(void *phl)
261 {
262 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
263 	struct phl_watchdog *wdog = &(phl_info->wdog);
264 
265 	_os_release_timer(phl_to_drvpriv(phl_info), &wdog->wdog_timer);
266 }
267 
rtw_phl_watchdog_start(void * phl)268 void rtw_phl_watchdog_start(void *phl)
269 {
270 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
271 	struct phl_watchdog *wdog = &(phl_info->wdog);
272 
273 	wdog->state = WD_STATE_STARTED;
274 	_phl_trigger_next_watchdog(phl_info);
275 }
276 
rtw_phl_watchdog_stop(void * phl)277 void rtw_phl_watchdog_stop(void *phl)
278 {
279 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
280 	struct phl_watchdog *wdog = &(phl_info->wdog);
281 
282 	PHL_INFO("%s\n", __func__);
283 
284 	wdog->state = WD_STATE_STOP;
285 
286 	_os_cancel_timer(phl_to_drvpriv(phl_info), &wdog->wdog_timer);
287 }
288