Loading drivers/esoc/esoc-mdm-4x.c +4 −1 Original line number Diff line number Diff line Loading @@ -101,7 +101,7 @@ static void mdm_enable_irqs(struct mdm_ctrl *mdm) } } static void mdm_disable_irqs(struct mdm_ctrl *mdm) void mdm_disable_irqs(struct mdm_ctrl *mdm) { if (!mdm) return; Loading Loading @@ -374,6 +374,9 @@ static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc) case ESOC_BOOT_FAIL: esoc_clink_evt_notify(ESOC_INVALID_STATE, esoc); break; case ESOC_PON_RETRY: esoc_clink_evt_notify(ESOC_RETRY_PON_EVT, esoc); break; case ESOC_UPGRADE_AVAILABLE: break; case ESOC_DEBUG_DONE: Loading drivers/esoc/esoc-mdm-drv.c +90 −47 Original line number Diff line number Diff line Loading @@ -16,8 +16,19 @@ #include <linux/of.h> #include <linux/esoc_client.h> #include "esoc.h" #include "esoc-mdm.h" #include "mdm-dbg.h" /* Maximum number of powerup trial requests per session */ #define ESOC_MAX_PON_REQ 2 enum esoc_pon_state { PON_INIT, PON_SUCCESS, PON_RETRY, PON_FAIL }; enum { PWR_OFF = 0x1, PWR_ON, Loading @@ -33,10 +44,10 @@ enum { struct mdm_drv { unsigned int mode; struct esoc_eng cmd_eng; struct completion boot_done; struct completion pon_done; struct completion req_eng_wait; struct esoc_clink *esoc_clink; bool boot_fail; enum esoc_pon_state pon_state; struct workqueue_struct *mdm_queue; struct work_struct ssr_work; struct notifier_block esoc_restart; Loading Loading @@ -66,18 +77,22 @@ static void mdm_handle_clink_evt(enum esoc_evt evt, switch (evt) { case ESOC_INVALID_STATE: mdm_drv->boot_fail = true; complete(&mdm_drv->boot_done); mdm_drv->pon_state = PON_FAIL; complete(&mdm_drv->pon_done); break; case ESOC_RUN_STATE: mdm_drv->boot_fail = false; mdm_drv->pon_state = PON_SUCCESS; mdm_drv->mode = RUN, complete(&mdm_drv->boot_done); complete(&mdm_drv->pon_done); break; case ESOC_RETRY_PON_EVT: mdm_drv->pon_state = PON_RETRY; complete(&mdm_drv->pon_done); break; case ESOC_UNEXPECTED_RESET: case ESOC_ERR_FATAL: /* * Modem can crash while we are waiting for boot_done during * Modem can crash while we are waiting for pon_done during * a subsystem_get(). Setting mode to CRASH will prevent a * subsequent subsystem_get() from entering poweron ops. Avoid * this by seting mode to CRASH only if device was up and Loading Loading @@ -205,6 +220,18 @@ static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys, return 0; } static void mdm_subsys_retry_powerup_cleanup(struct esoc_clink *esoc_clink) { struct mdm_ctrl *mdm = get_esoc_clink_data(esoc_clink); struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); esoc_client_link_power_off(esoc_clink, false); mdm_disable_irqs(mdm); mdm_drv->pon_state = PON_INIT; reinit_completion(&mdm_drv->pon_done); reinit_completion(&mdm_drv->req_eng_wait); } static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) { int ret; Loading @@ -213,10 +240,15 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) subsys); struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); const struct esoc_clink_ops * const clink_ops = esoc_clink->clink_ops; struct mdm_ctrl *mdm = get_esoc_clink_data(esoc_clink); int timeout = INT_MAX; u8 pon_trial = 1; if (!esoc_clink->auto_boot && !esoc_req_eng_enabled(esoc_clink)) { dev_dbg(&esoc_clink->dev, "Wait for req eng registration\n"); do { if (!esoc_clink->auto_boot && !esoc_req_eng_enabled(esoc_clink)) { dev_dbg(&esoc_clink->dev, "Wait for req eng registration\n"); wait_for_completion(&mdm_drv->req_eng_wait); } if (mdm_drv->mode == PWR_OFF) { Loading @@ -231,7 +263,8 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) } else if (mdm_drv->mode == IN_DEBUG) { ret = clink_ops->cmd_exe(ESOC_EXIT_DEBUG, esoc_clink); if (ret) { dev_err(&esoc_clink->dev, "cannot exit debug mode\n"); dev_err(&esoc_clink->dev, "cannot exit debug mode\n"); return ret; } mdm_drv->mode = PWR_OFF; Loading @@ -245,17 +278,27 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) /* * In autoboot case, it is possible that we can forever wait for * boot completion, when esoc fails to boot. This is because there * is no helper application which can alert esoc driver about boot * failure. Prevent going to wait forever in such case. * boot completion, when esoc fails to boot. This is because * there is no helper application which can alert esoc driver * about boot failure. Prevent going to wait forever in such * case. */ if (esoc_clink->auto_boot) timeout = 10 * HZ; ret = wait_for_completion_timeout(&mdm_drv->boot_done, timeout); if (mdm_drv->boot_fail || ret <= 0) { ret = wait_for_completion_timeout(&mdm_drv->pon_done, timeout); if (mdm_drv->pon_state == PON_FAIL || ret <= 0) { dev_err(&esoc_clink->dev, "booting failed\n"); mdm_subsys_retry_powerup_cleanup(esoc_clink); mdm_power_down(mdm); return -EIO; } else if (mdm_drv->pon_state == PON_RETRY) { pon_trial++; mdm_subsys_retry_powerup_cleanup(esoc_clink); } else if (mdm_drv->pon_state == PON_SUCCESS) { break; } } while (pon_trial <= ESOC_MAX_PON_REQ); return 0; } Loading Loading @@ -314,12 +357,12 @@ int esoc_ssr_probe(struct esoc_clink *esoc_clink, struct esoc_drv *drv) goto queue_err; } esoc_set_drv_data(esoc_clink, mdm_drv); init_completion(&mdm_drv->boot_done); init_completion(&mdm_drv->pon_done); init_completion(&mdm_drv->req_eng_wait); INIT_WORK(&mdm_drv->ssr_work, mdm_ssr_fn); mdm_drv->esoc_clink = esoc_clink; mdm_drv->mode = PWR_OFF; mdm_drv->boot_fail = false; mdm_drv->pon_state = PON_INIT; mdm_drv->esoc_restart.notifier_call = esoc_msm_restart_handler; ret = register_reboot_notifier(&mdm_drv->esoc_restart); if (ret) Loading drivers/esoc/esoc-mdm.h +2 −0 Original line number Diff line number Diff line Loading @@ -123,6 +123,8 @@ struct mdm_ops { struct platform_device *pdev); }; void mdm_disable_irqs(struct mdm_ctrl *mdm); static inline int mdm_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic) { return mdm->pon_ops->soft_reset(mdm, atomic); Loading include/uapi/linux/esoc_ctrl.h +3 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ struct esoc_link_data { #define ESOC_REQ_SEND_SHUTDOWN ESOC_REQ_SEND_SHUTDOWN #define ESOC_REQ_CRASH_SHUTDOWN ESOC_REQ_CRASH_SHUTDOWN #define ESOC_PON_RETRY ESOC_PON_RETRY enum esoc_evt { ESOC_RUN_STATE = 0x1, Loading @@ -38,6 +39,7 @@ enum esoc_evt { ESOC_CMD_ENG_ON, ESOC_CMD_ENG_OFF, ESOC_INVALID_STATE, ESOC_RETRY_PON_EVT, }; enum esoc_cmd { Loading @@ -61,6 +63,7 @@ enum esoc_notify { ESOC_DEBUG_FAIL, ESOC_PRIMARY_CRASH, ESOC_PRIMARY_REBOOT, ESOC_PON_RETRY, }; enum esoc_req { Loading Loading
drivers/esoc/esoc-mdm-4x.c +4 −1 Original line number Diff line number Diff line Loading @@ -101,7 +101,7 @@ static void mdm_enable_irqs(struct mdm_ctrl *mdm) } } static void mdm_disable_irqs(struct mdm_ctrl *mdm) void mdm_disable_irqs(struct mdm_ctrl *mdm) { if (!mdm) return; Loading Loading @@ -374,6 +374,9 @@ static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc) case ESOC_BOOT_FAIL: esoc_clink_evt_notify(ESOC_INVALID_STATE, esoc); break; case ESOC_PON_RETRY: esoc_clink_evt_notify(ESOC_RETRY_PON_EVT, esoc); break; case ESOC_UPGRADE_AVAILABLE: break; case ESOC_DEBUG_DONE: Loading
drivers/esoc/esoc-mdm-drv.c +90 −47 Original line number Diff line number Diff line Loading @@ -16,8 +16,19 @@ #include <linux/of.h> #include <linux/esoc_client.h> #include "esoc.h" #include "esoc-mdm.h" #include "mdm-dbg.h" /* Maximum number of powerup trial requests per session */ #define ESOC_MAX_PON_REQ 2 enum esoc_pon_state { PON_INIT, PON_SUCCESS, PON_RETRY, PON_FAIL }; enum { PWR_OFF = 0x1, PWR_ON, Loading @@ -33,10 +44,10 @@ enum { struct mdm_drv { unsigned int mode; struct esoc_eng cmd_eng; struct completion boot_done; struct completion pon_done; struct completion req_eng_wait; struct esoc_clink *esoc_clink; bool boot_fail; enum esoc_pon_state pon_state; struct workqueue_struct *mdm_queue; struct work_struct ssr_work; struct notifier_block esoc_restart; Loading Loading @@ -66,18 +77,22 @@ static void mdm_handle_clink_evt(enum esoc_evt evt, switch (evt) { case ESOC_INVALID_STATE: mdm_drv->boot_fail = true; complete(&mdm_drv->boot_done); mdm_drv->pon_state = PON_FAIL; complete(&mdm_drv->pon_done); break; case ESOC_RUN_STATE: mdm_drv->boot_fail = false; mdm_drv->pon_state = PON_SUCCESS; mdm_drv->mode = RUN, complete(&mdm_drv->boot_done); complete(&mdm_drv->pon_done); break; case ESOC_RETRY_PON_EVT: mdm_drv->pon_state = PON_RETRY; complete(&mdm_drv->pon_done); break; case ESOC_UNEXPECTED_RESET: case ESOC_ERR_FATAL: /* * Modem can crash while we are waiting for boot_done during * Modem can crash while we are waiting for pon_done during * a subsystem_get(). Setting mode to CRASH will prevent a * subsequent subsystem_get() from entering poweron ops. Avoid * this by seting mode to CRASH only if device was up and Loading Loading @@ -205,6 +220,18 @@ static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys, return 0; } static void mdm_subsys_retry_powerup_cleanup(struct esoc_clink *esoc_clink) { struct mdm_ctrl *mdm = get_esoc_clink_data(esoc_clink); struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); esoc_client_link_power_off(esoc_clink, false); mdm_disable_irqs(mdm); mdm_drv->pon_state = PON_INIT; reinit_completion(&mdm_drv->pon_done); reinit_completion(&mdm_drv->req_eng_wait); } static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) { int ret; Loading @@ -213,10 +240,15 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) subsys); struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); const struct esoc_clink_ops * const clink_ops = esoc_clink->clink_ops; struct mdm_ctrl *mdm = get_esoc_clink_data(esoc_clink); int timeout = INT_MAX; u8 pon_trial = 1; if (!esoc_clink->auto_boot && !esoc_req_eng_enabled(esoc_clink)) { dev_dbg(&esoc_clink->dev, "Wait for req eng registration\n"); do { if (!esoc_clink->auto_boot && !esoc_req_eng_enabled(esoc_clink)) { dev_dbg(&esoc_clink->dev, "Wait for req eng registration\n"); wait_for_completion(&mdm_drv->req_eng_wait); } if (mdm_drv->mode == PWR_OFF) { Loading @@ -231,7 +263,8 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) } else if (mdm_drv->mode == IN_DEBUG) { ret = clink_ops->cmd_exe(ESOC_EXIT_DEBUG, esoc_clink); if (ret) { dev_err(&esoc_clink->dev, "cannot exit debug mode\n"); dev_err(&esoc_clink->dev, "cannot exit debug mode\n"); return ret; } mdm_drv->mode = PWR_OFF; Loading @@ -245,17 +278,27 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) /* * In autoboot case, it is possible that we can forever wait for * boot completion, when esoc fails to boot. This is because there * is no helper application which can alert esoc driver about boot * failure. Prevent going to wait forever in such case. * boot completion, when esoc fails to boot. This is because * there is no helper application which can alert esoc driver * about boot failure. Prevent going to wait forever in such * case. */ if (esoc_clink->auto_boot) timeout = 10 * HZ; ret = wait_for_completion_timeout(&mdm_drv->boot_done, timeout); if (mdm_drv->boot_fail || ret <= 0) { ret = wait_for_completion_timeout(&mdm_drv->pon_done, timeout); if (mdm_drv->pon_state == PON_FAIL || ret <= 0) { dev_err(&esoc_clink->dev, "booting failed\n"); mdm_subsys_retry_powerup_cleanup(esoc_clink); mdm_power_down(mdm); return -EIO; } else if (mdm_drv->pon_state == PON_RETRY) { pon_trial++; mdm_subsys_retry_powerup_cleanup(esoc_clink); } else if (mdm_drv->pon_state == PON_SUCCESS) { break; } } while (pon_trial <= ESOC_MAX_PON_REQ); return 0; } Loading Loading @@ -314,12 +357,12 @@ int esoc_ssr_probe(struct esoc_clink *esoc_clink, struct esoc_drv *drv) goto queue_err; } esoc_set_drv_data(esoc_clink, mdm_drv); init_completion(&mdm_drv->boot_done); init_completion(&mdm_drv->pon_done); init_completion(&mdm_drv->req_eng_wait); INIT_WORK(&mdm_drv->ssr_work, mdm_ssr_fn); mdm_drv->esoc_clink = esoc_clink; mdm_drv->mode = PWR_OFF; mdm_drv->boot_fail = false; mdm_drv->pon_state = PON_INIT; mdm_drv->esoc_restart.notifier_call = esoc_msm_restart_handler; ret = register_reboot_notifier(&mdm_drv->esoc_restart); if (ret) Loading
drivers/esoc/esoc-mdm.h +2 −0 Original line number Diff line number Diff line Loading @@ -123,6 +123,8 @@ struct mdm_ops { struct platform_device *pdev); }; void mdm_disable_irqs(struct mdm_ctrl *mdm); static inline int mdm_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic) { return mdm->pon_ops->soft_reset(mdm, atomic); Loading
include/uapi/linux/esoc_ctrl.h +3 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ struct esoc_link_data { #define ESOC_REQ_SEND_SHUTDOWN ESOC_REQ_SEND_SHUTDOWN #define ESOC_REQ_CRASH_SHUTDOWN ESOC_REQ_CRASH_SHUTDOWN #define ESOC_PON_RETRY ESOC_PON_RETRY enum esoc_evt { ESOC_RUN_STATE = 0x1, Loading @@ -38,6 +39,7 @@ enum esoc_evt { ESOC_CMD_ENG_ON, ESOC_CMD_ENG_OFF, ESOC_INVALID_STATE, ESOC_RETRY_PON_EVT, }; enum esoc_cmd { Loading @@ -61,6 +63,7 @@ enum esoc_notify { ESOC_DEBUG_FAIL, ESOC_PRIMARY_CRASH, ESOC_PRIMARY_REBOOT, ESOC_PON_RETRY, }; enum esoc_req { Loading