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