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