1 /* Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved.
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
13 #include <linux/delay.h>
14 #include <linux/workqueue.h>
15 #include <linux/reboot.h>
34 struct esoc_eng cmd_eng;
35 struct completion boot_done;
36 struct completion req_eng_wait;
37 struct esoc_clink *esoc_clink;
39 struct workqueue_struct *mdm_queue;
40 struct work_struct ssr_work;
41 struct notifier_block esoc_restart;
43 #define to_mdm_drv(d) container_of(d, struct mdm_drv, cmd_eng)
45 static int esoc_msm_restart_handler(struct notifier_block *nb,
46 unsigned long action, void *data)
48 struct mdm_drv *mdm_drv = container_of(nb, struct mdm_drv,
50 struct esoc_clink *esoc_clink = mdm_drv->esoc_clink;
51 const struct esoc_clink_ops const *clink_ops = esoc_clink->clink_ops;
52 if (action == SYS_RESTART) {
53 if (mdm_dbg_stall_notify(ESOC_PRIMARY_REBOOT))
55 dev_dbg(&esoc_clink->dev, "Notifying esoc of cold reboot\n");
56 clink_ops->notify(ESOC_PRIMARY_REBOOT, esoc_clink);
60 static void mdm_handle_clink_evt(enum esoc_evt evt,
63 struct mdm_drv *mdm_drv = to_mdm_drv(eng);
65 case ESOC_INVALID_STATE:
66 mdm_drv->boot_fail = true;
67 complete(&mdm_drv->boot_done);
70 mdm_drv->boot_fail = false;
72 complete(&mdm_drv->boot_done);
74 case ESOC_UNEXPECTED_RESET:
77 * Modem can crash while we are waiting for boot_done during
78 * a subsystem_get(). Setting mode to CRASH will prevent a
79 * subsequent subsystem_get() from entering poweron ops. Avoid
80 * this by seting mode to CRASH only if device was up and
83 if (mdm_drv->mode == CRASH || mdm_drv->mode != RUN)
85 mdm_drv->mode = CRASH;
86 queue_work(mdm_drv->mdm_queue, &mdm_drv->ssr_work);
89 complete(&mdm_drv->req_eng_wait);
96 static void mdm_ssr_fn(struct work_struct *work)
98 struct mdm_drv *mdm_drv = container_of(work, struct mdm_drv, ssr_work);
101 * If restarting esoc fails, the SSR framework triggers a kernel panic
103 esoc_clink_request_ssr(mdm_drv->esoc_clink);
107 static void mdm_crash_shutdown(const struct subsys_desc *mdm_subsys)
109 struct esoc_clink *esoc_clink =
110 container_of(mdm_subsys,
113 const struct esoc_clink_ops const *clink_ops = esoc_clink->clink_ops;
114 if (mdm_dbg_stall_notify(ESOC_PRIMARY_CRASH))
116 clink_ops->notify(ESOC_PRIMARY_CRASH, esoc_clink);
119 static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys,
123 struct esoc_clink *esoc_clink =
124 container_of(crashed_subsys, struct esoc_clink, subsys);
125 struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink);
126 const struct esoc_clink_ops const *clink_ops = esoc_clink->clink_ops;
128 if (mdm_drv->mode == CRASH || mdm_drv->mode == PEER_CRASH) {
129 if (mdm_dbg_stall_cmd(ESOC_PREPARE_DEBUG))
130 /* We want to mask debug command.
131 * In this case return success
132 * to move to next stage
135 ret = clink_ops->cmd_exe(ESOC_PREPARE_DEBUG,
138 dev_err(&esoc_clink->dev, "failed to enter debug\n");
141 mdm_drv->mode = IN_DEBUG;
142 } else if (!force_stop) {
143 if (esoc_clink->subsys.sysmon_shutdown_ret)
144 ret = clink_ops->cmd_exe(ESOC_FORCE_PWR_OFF,
147 if (mdm_dbg_stall_cmd(ESOC_PWR_OFF))
148 /* Since power off command is masked
149 * we return success, and leave the state
150 * of the command engine as is.
153 ret = clink_ops->cmd_exe(ESOC_PWR_OFF, esoc_clink);
156 dev_err(&esoc_clink->dev, "failed to exe power off\n");
159 mdm_drv->mode = PWR_OFF;
164 static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
167 struct esoc_clink *esoc_clink =
168 container_of(crashed_subsys, struct esoc_clink,
170 struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink);
171 const struct esoc_clink_ops const *clink_ops = esoc_clink->clink_ops;
172 int timeout = INT_MAX;
174 if (!esoc_clink->auto_boot && !esoc_req_eng_enabled(esoc_clink)) {
175 dev_dbg(&esoc_clink->dev, "Wait for req eng registration\n");
176 wait_for_completion(&mdm_drv->req_eng_wait);
178 if (mdm_drv->mode == PWR_OFF) {
179 if (mdm_dbg_stall_cmd(ESOC_PWR_ON))
181 ret = clink_ops->cmd_exe(ESOC_PWR_ON, esoc_clink);
183 dev_err(&esoc_clink->dev, "pwr on fail\n");
186 } else if (mdm_drv->mode == IN_DEBUG) {
187 ret = clink_ops->cmd_exe(ESOC_EXIT_DEBUG, esoc_clink);
189 dev_err(&esoc_clink->dev, "cannot exit debug mode\n");
192 mdm_drv->mode = PWR_OFF;
193 ret = clink_ops->cmd_exe(ESOC_PWR_ON, esoc_clink);
195 dev_err(&esoc_clink->dev, "pwr on fail\n");
201 * In autoboot case, it is possible that we can forever wait for
202 * boot completion, when esoc fails to boot. This is because there
203 * is no helper application which can alert esoc driver about boot
204 * failure. Prevent going to wait forever in such case.
206 if (esoc_clink->auto_boot)
208 ret = wait_for_completion_timeout(&mdm_drv->boot_done, timeout);
209 if (mdm_drv->boot_fail || ret <= 0) {
210 dev_err(&esoc_clink->dev, "booting failed\n");
216 static int mdm_subsys_ramdumps(int want_dumps,
217 const struct subsys_desc *crashed_subsys)
220 struct esoc_clink *esoc_clink =
221 container_of(crashed_subsys, struct esoc_clink,
223 const struct esoc_clink_ops const *clink_ops = esoc_clink->clink_ops;
226 ret = clink_ops->cmd_exe(ESOC_EXE_DEBUG, esoc_clink);
228 dev_err(&esoc_clink->dev, "debugging failed\n");
235 static int mdm_register_ssr(struct esoc_clink *esoc_clink)
237 struct subsys_desc *subsys = &esoc_clink->subsys;
239 subsys->shutdown = mdm_subsys_shutdown;
240 subsys->ramdump = mdm_subsys_ramdumps;
241 subsys->powerup = mdm_subsys_powerup;
242 subsys->crash_shutdown = mdm_crash_shutdown;
243 return esoc_clink_register_ssr(esoc_clink);
246 int esoc_ssr_probe(struct esoc_clink *esoc_clink, struct esoc_drv *drv)
249 struct mdm_drv *mdm_drv;
250 struct esoc_eng *esoc_eng;
252 mdm_drv = devm_kzalloc(&esoc_clink->dev, sizeof(*mdm_drv), GFP_KERNEL);
253 if (IS_ERR_OR_NULL(mdm_drv))
254 return PTR_ERR(mdm_drv);
255 esoc_eng = &mdm_drv->cmd_eng;
256 esoc_eng->handle_clink_evt = mdm_handle_clink_evt;
257 ret = esoc_clink_register_cmd_eng(esoc_clink, esoc_eng);
259 dev_err(&esoc_clink->dev, "failed to register cmd engine\n");
262 ret = mdm_register_ssr(esoc_clink);
265 mdm_drv->mdm_queue = alloc_workqueue("mdm_drv_queue", 0, 0);
266 if (!mdm_drv->mdm_queue) {
267 dev_err(&esoc_clink->dev, "could not create mdm_queue\n");
270 esoc_set_drv_data(esoc_clink, mdm_drv);
271 init_completion(&mdm_drv->boot_done);
272 init_completion(&mdm_drv->req_eng_wait);
273 INIT_WORK(&mdm_drv->ssr_work, mdm_ssr_fn);
274 mdm_drv->esoc_clink = esoc_clink;
275 mdm_drv->mode = PWR_OFF;
276 mdm_drv->boot_fail = false;
277 mdm_drv->esoc_restart.notifier_call = esoc_msm_restart_handler;
278 ret = register_reboot_notifier(&mdm_drv->esoc_restart);
280 dev_err(&esoc_clink->dev, "register for reboot failed\n");
281 ret = mdm_dbg_eng_init(drv, esoc_clink);
283 debug_init_done = false;
284 dev_err(&esoc_clink->dev, "dbg engine failure\n");
286 dev_dbg(&esoc_clink->dev, "dbg engine initialized\n");
287 debug_init_done = true;
291 esoc_clink_unregister_ssr(esoc_clink);
293 esoc_clink_unregister_cmd_eng(esoc_clink, esoc_eng);
297 static struct esoc_compat compat_table[] = {
311 static struct esoc_drv esoc_ssr_drv = {
312 .owner = THIS_MODULE,
313 .probe = esoc_ssr_probe,
314 .compat_table = compat_table,
315 .compat_entries = ARRAY_SIZE(compat_table),
321 int __init esoc_ssr_init(void)
323 return esoc_drv_register(&esoc_ssr_drv);
325 module_init(esoc_ssr_init);
326 MODULE_LICENSE("GPL v2");