diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c index 1645d10bd781..353bcfe2114f 100644 --- a/drivers/esoc/esoc-mdm-drv.c +++ b/drivers/esoc/esoc-mdm-drv.c @@ -20,25 +20,11 @@ #include "mdm-dbg.h" /* Default number of powerup trial requests per session */ -#define ESOC_DEF_PON_REQ 2 -static unsigned int n_pon_tries = ESOC_DEF_PON_REQ; -module_param(n_pon_tries, uint, 0644); -MODULE_PARM_DESC(n_pon_tries, -"Number of power-on retrials allowed upon boot failure"); +#define ESOC_DEF_PON_REQ 3 -enum esoc_boot_fail_action { - BOOT_FAIL_ACTION_RETRY, - BOOT_FAIL_ACTION_COLD_RESET, - BOOT_FAIL_ACTION_SHUTDOWN, - BOOT_FAIL_ACTION_PANIC, - BOOT_FAIL_ACTION_NOP, - BOOT_FAIL_ACTION_S3_RESET, -}; +#define ESOC_MAX_PON_TRIES 5 -static unsigned int boot_fail_action = BOOT_FAIL_ACTION_PANIC; -module_param(boot_fail_action, uint, 0644); -MODULE_PARM_DESC(boot_fail_action, -"Actions: 0:Retry PON; 1:Cold reset; 2:Power-down; 3:APQ Panic; 4:No action"); +#define BOOT_FAIL_ACTION_DEF BOOT_FAIL_ACTION_PANIC enum esoc_pon_state { PON_INIT, @@ -70,14 +56,58 @@ struct mdm_drv { struct work_struct ssr_work; struct notifier_block esoc_restart; struct mutex poff_lock; + atomic_t boot_fail_action; + atomic_t n_pon_tries; }; #define to_mdm_drv(d) container_of(d, struct mdm_drv, cmd_eng) -#define S3_RESET_DELAY_MS 2100 +#define S3_RESET_DELAY_MS 2000 static void esoc_client_link_power_off(struct esoc_clink *esoc_clink, unsigned int flags); +int esoc_set_boot_fail_action(struct esoc_clink *esoc_clink, u32 action) +{ + struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); + + if (action >= BOOT_FAIL_ACTION_LAST) { + esoc_mdm_log("Unknown boot fail action requested: %u\n", + action); + return -EINVAL; + } + + if (!mdm_drv) { + esoc_mdm_log("esoc-mdm driver not present\n"); + return -EAGAIN; + } + + atomic_set(&mdm_drv->boot_fail_action, action); + esoc_mdm_log("Boot fail action configured to %u\n", action); + + return 0; +} + +int esoc_set_n_pon_tries(struct esoc_clink *esoc_clink, u32 n_tries) +{ + struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); + + if (n_tries > ESOC_MAX_PON_TRIES) { + esoc_mdm_log( + "Num PON tries requested (%u) is over the limit: %u\n", + n_tries, ESOC_MAX_PON_TRIES); + } + + if (!mdm_drv) { + esoc_mdm_log("esoc-mdm driver not present\n"); + return -EAGAIN; + } + + atomic_set(&mdm_drv->n_pon_tries, n_tries); + esoc_mdm_log("Num PON tries configured to %u\n", n_tries); + + return 0; +} + static int esoc_msm_restart_handler(struct notifier_block *nb, unsigned long action, void *data) { @@ -327,8 +357,15 @@ static void mdm_subsys_retry_powerup_cleanup(struct esoc_clink *esoc_clink, static int mdm_handle_boot_fail(struct esoc_clink *esoc_clink, u8 *pon_trial) { struct mdm_ctrl *mdm = get_esoc_clink_data(esoc_clink); + struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); - switch (boot_fail_action) { + if (*pon_trial == atomic_read(&mdm_drv->n_pon_tries)) { + esoc_mdm_log("Reached max. number of boot trials\n"); + atomic_set(&mdm_drv->boot_fail_action, + BOOT_FAIL_ACTION_PANIC); + } + + switch (atomic_read(&mdm_drv->boot_fail_action)) { case BOOT_FAIL_ACTION_RETRY: mdm_subsys_retry_powerup_cleanup(esoc_clink, 0); esoc_mdm_log("Request to retry a warm reset\n"); @@ -382,7 +419,7 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink); const struct esoc_clink_ops * const clink_ops = esoc_clink->clink_ops; int timeout = INT_MAX; - u8 pon_trial = 1; + u8 pon_trial = 0; esoc_mdm_log("Powerup request from SSR\n"); @@ -456,7 +493,7 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys) } else if (mdm_drv->pon_state == PON_SUCCESS) { break; } - } while (pon_trial <= n_pon_tries); + } while (pon_trial <= atomic_read(&mdm_drv->n_pon_tries)); return 0; } @@ -528,6 +565,8 @@ int esoc_ssr_probe(struct esoc_clink *esoc_clink, struct esoc_drv *drv) mdm_drv->esoc_clink = esoc_clink; mdm_drv->mode = PWR_OFF; mdm_drv->pon_state = PON_INIT; + atomic_set(&mdm_drv->boot_fail_action, BOOT_FAIL_ACTION_DEF); + atomic_set(&mdm_drv->n_pon_tries, ESOC_DEF_PON_REQ); mdm_drv->esoc_restart.notifier_call = esoc_msm_restart_handler; ret = register_reboot_notifier(&mdm_drv->esoc_restart); if (ret) diff --git a/drivers/esoc/esoc.h b/drivers/esoc/esoc.h index 81dd0dfe1cad..46403c371698 100644 --- a/drivers/esoc/esoc.h +++ b/drivers/esoc/esoc.h @@ -193,3 +193,7 @@ static inline void notify_esoc_clients(struct esoc_clink *esoc_clink, bool esoc_req_eng_enabled(struct esoc_clink *esoc_clink); bool esoc_cmd_eng_enabled(struct esoc_clink *esoc_clink); #endif + +/* Modem boot fail actions */ +int esoc_set_boot_fail_action(struct esoc_clink *esoc_clink, u32 action); +int esoc_set_n_pon_tries(struct esoc_clink *esoc_clink, u32 n_tries); diff --git a/drivers/esoc/esoc_dev.c b/drivers/esoc/esoc_dev.c index 6777627daee5..bd3929074eea 100644 --- a/drivers/esoc/esoc_dev.c +++ b/drivers/esoc/esoc_dev.c @@ -330,6 +330,12 @@ static long esoc_dev_ioctl(struct file *file, unsigned int cmd, return err; case ESOC_GET_LINK_ID: return esoc_get_link_id(esoc_clink, arg); + case ESOC_SET_BOOT_FAIL_ACT: + get_user(esoc_cmd, (u32 __user *) arg); + return esoc_set_boot_fail_action(esoc_clink, esoc_cmd); + case ESOC_SET_N_PON_TRIES: + get_user(esoc_cmd, (u32 __user *) arg); + return esoc_set_n_pon_tries(esoc_clink, esoc_cmd); default: return -EINVAL; }; diff --git a/include/uapi/linux/esoc_ctrl.h b/include/uapi/linux/esoc_ctrl.h index 9761aa1ae3b0..631fa449c386 100644 --- a/include/uapi/linux/esoc_ctrl.h +++ b/include/uapi/linux/esoc_ctrl.h @@ -14,12 +14,25 @@ #define ESOC_REG_REQ_ENG _IO(ESOC_CODE, 7) #define ESOC_REG_CMD_ENG _IO(ESOC_CODE, 8) #define ESOC_GET_LINK_ID _IOWR(ESOC_CODE, 9, __u64) +#define ESOC_SET_BOOT_FAIL_ACT _IOW(ESOC_CODE, 10, unsigned int) +#define ESOC_SET_N_PON_TRIES _IOW(ESOC_CODE, 11, unsigned int) #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 +#define ESOC_BOOT_FAIL_ACTION #define ESOC_LINK_ID +enum esoc_boot_fail_action { + BOOT_FAIL_ACTION_RETRY, + BOOT_FAIL_ACTION_COLD_RESET, + BOOT_FAIL_ACTION_SHUTDOWN, + BOOT_FAIL_ACTION_PANIC, + BOOT_FAIL_ACTION_NOP, + BOOT_FAIL_ACTION_S3_RESET, + BOOT_FAIL_ACTION_LAST, +}; + enum esoc_evt { ESOC_RUN_STATE = 0x1, ESOC_UNEXPECTED_RESET,