1 /*
2 * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 /* ****************************************************************************
20 1 头文件包含
21 **************************************************************************** */
22 #include <linux/delay.h>
23 #include <linux/rtc.h>
24
25 #include "plat_pm.h"
26 #include "plat_pm_wlan.h"
27 #include "exception_rst.h"
28 #include "plat_firmware.h"
29 #include "oal_file.h"
30 #include "oal_sdio_host_if.h"
31 #include "hcc_host.h"
32 #include "oam_ext_if.h"
33 #include "oal_chr.h"
34
35 /* ****************************************************************************
36 3 全局变量定义
37 **************************************************************************** */
38 struct st_exception_info *g_pst_exception_info = HI_NULL;
39
40 static hi_u8 g_dev_pannic = HI_FALSE;
41
oal_wakeup_exception(void)42 void oal_wakeup_exception(void)
43 {
44 unsigned long flags;
45
46 if (g_pst_exception_info == HI_NULL) {
47 printk("[E]%s, g_pst_exception_info is null\n", __FUNCTION__);
48 return;
49 }
50
51 oal_spin_lock_irq_save(&(g_pst_exception_info->excp_lock), &flags);
52 if (work_busy(&(g_pst_exception_info->excp_worker))) {
53 oal_spin_unlock_irq_restore(&g_pst_exception_info->excp_lock, &flags);
54 return;
55 }
56
57 g_pst_exception_info->excetion_type = TRANS_FAIL;
58 schedule_work(&(g_pst_exception_info->excp_worker));
59 oal_spin_unlock_irq_restore(&(g_pst_exception_info->excp_lock), &flags);
60 }
61
oal_exception_submit(hi_s32 excep_type)62 void oal_exception_submit(hi_s32 excep_type)
63 {
64 unsigned long flags;
65
66 if (g_pst_exception_info == NULL) {
67 printk("[E]%s, g_pst_exception_info is null\n", __FUNCTION__);
68 return;
69 }
70
71 if (wlan_pm_is_shutdown()) {
72 return;
73 }
74
75 if (HOST_ALLOW_TO_SLEEP == wlan_pm_state_get()) {
76 return;
77 }
78 wlan_pm_set_pm_sts_exception();
79 oal_spin_lock_irq_save(&(g_pst_exception_info->excp_lock), &flags);
80 if (work_busy(&(g_pst_exception_info->excp_worker))) {
81 printk("excep %d block, exception %d is working\n", excep_type, g_pst_exception_info->excetion_type);
82 oal_spin_unlock_irq_restore(&g_pst_exception_info->excp_lock, &flags);
83 return;
84 }
85
86 g_pst_exception_info->excetion_type = excep_type;
87 schedule_work(&(g_pst_exception_info->excp_worker));
88 oal_spin_unlock_irq_restore(&(g_pst_exception_info->excp_lock), &flags);
89 }
90
oal_exception_is_busy(void)91 hi_s32 oal_exception_is_busy(void)
92 {
93 if (oal_unlikely(g_pst_exception_info == NULL)) {
94 return HI_FALSE;
95 }
96
97 if (work_busy(&(g_pst_exception_info->excp_worker))) {
98 /* sdio mem dump is processing, can't power off or submit repeat */
99 return HI_TRUE;
100 }
101
102 return HI_FALSE;
103 }
104
oal_trigger_exception(hi_s32 is_sync)105 hi_s32 oal_trigger_exception(hi_s32 is_sync)
106 {
107 unsigned long timeout_jiffies;
108 struct BusDev *bus = oal_get_bus_default_handler();
109 if (oal_exception_is_busy() == HI_TRUE) {
110 return HI_TRUE;
111 }
112 printk("oal_trigger_exception start\n");
113 /* trigger device panic */
114 if (oal_bus_send_msg(bus, H2D_MSG_TEST) != HI_SUCCESS) {
115 printk("send sdio panic message failed!\n");
116 return HI_FALSE;
117 }
118
119 if (is_sync != HI_TRUE) {
120 printk("sdio exception is doing...\n");
121 return HI_TRUE;
122 }
123
124 /* wait device panic */
125 timeout_jiffies = OAL_TIME_JIFFY + OAL_MSECS_TO_JIFFIES(2000); /* jiffies 2000 */
126 for (;;) {
127 if (oal_exception_is_busy() == HI_TRUE) {
128 break;
129 }
130
131 if (oal_time_after(OAL_TIME_JIFFY, timeout_jiffies) > 0) {
132 printk("wait panic message timeout!\n");
133 return HI_FALSE;
134 }
135
136 oal_msleep(OAL_JIFFIES_TO_MSECS(1));
137 }
138
139 printk("trigger sdio exception manually sucuess\n");
140 return HI_TRUE;
141 }
142
143 /* Try to dump device mem, controlled by flag sdio_dump_mem_flag */
oal_try_to_dump_device_mem(hi_s32 is_sync)144 void oal_try_to_dump_device_mem(hi_s32 is_sync)
145 {
146 hi_s32 ret;
147 if ((g_pst_exception_info->dump_mem_flag) == NOT_DUMP_MEM) {
148 printk("sdio_dump_mem_flag is NOT_DUMP_MEM\r\n");
149 return;
150 }
151
152 printk("Try to dump device mem!\n");
153 ret = oal_trigger_exception(is_sync);
154 if (ret != HI_TRUE) {
155 printk("call oal_trigger_exception fail!\n");
156 }
157 }
158
oal_set_dev_panic(hi_void)159 hi_void oal_set_dev_panic(hi_void)
160 {
161 g_dev_pannic = HI_TRUE;
162 }
163
oal_clear_dev_panic(hi_void)164 hi_void oal_clear_dev_panic(hi_void)
165 {
166 g_dev_pannic = HI_FALSE;
167 }
168
oal_dev_is_panic(hi_void)169 hi_u8 oal_dev_is_panic(hi_void)
170 {
171 return g_dev_pannic;
172 }
173
oal_device_panic_callback(void * data)174 hi_s32 oal_device_panic_callback(void *data)
175 {
176 hi_unref_param(data);
177 oam_error_log0(0, 0, "=======device_panic=========\n");
178 oal_set_dev_panic();
179 oal_exception_submit(DEVICE_PANIC);
180 if (hisi_sched_event(DEV_PANIC) != HI_SUCCESS) {
181 printk("DEV_PANIC event notification failed\n");
182 }
183 return HI_SUCCESS;
184 }
185
oal_frw_exception_report(hi_void)186 hi_void oal_frw_exception_report(hi_void)
187 {
188 if (hisi_sched_event(DRIVER_HUNG) != HI_SUCCESS) {
189 printk("FRW_ENQUEUE_FAIL event notification failed\n");
190 }
191 }
192