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