static void log_modem_sfr(void)
{
	u32 size;
	char *smem_reason, reason[MAX_SSR_REASON_LEN];

	smem_reason = smem_get_entry_no_rlock(SMEM_SSR_REASON_MSS0, &size);
	if (!smem_reason || !size) {
		pr_err("modem subsystem failure reason: (unknown, smem_get_entry_no_rlock failed).\n");
		return;
	}
	if (!smem_reason[0]) {
		pr_err("modem subsystem failure reason: (unknown, empty string found).\n");
		return;
	}

	strlcpy(reason, smem_reason, min(size, sizeof(reason)));
	pr_err("modem subsystem failure reason: %s.\n", reason);
#if defined(CONFIG_PRE_SELF_DIAGNOSIS)
	lge_pre_self_diagnosis((char *) "modem",3,(char *) "modem failed",(char *) reason, 20001);
#endif

#ifdef FEATURE_LGE_MODEM_DEBUG_INFO
    if (modem_debug.modem_ssr_level != RESET_SOC) {
        strlcpy(modem_debug.save_ssr_reason, smem_reason, min(size, sizeof(reason)));
        modem_debug.modem_ssr_event = MODEM_SSR_ERR_FATAL;
        queue_work(modem_debug.modem_ssr_queue, &modem_debug.modem_ssr_report_work);
    }
#endif

    smem_reason[0] = '\0';
    wmb();

}
/* [END] [email protected], SSR FEATURE */
static void log_modem_sfr(void)
{
	u32 size;
	char *smem_reason, reason[MAX_SSR_REASON_LEN];

	smem_reason = smem_get_entry_no_rlock(SMEM_SSR_REASON_MSS0, &size);
	if (!smem_reason || !size) {
		pr_err("modem subsystem failure reason: (unknown, smem_get_entry_no_rlock failed).\n");
		return;
	}
	if (!smem_reason[0]) {
		pr_err("modem subsystem failure reason: (unknown, empty string found).\n");
		return;
	}

	strlcpy(reason, smem_reason, min(size, sizeof(reason)));
	pr_err("modem subsystem failure reason: %s.\n", reason);
#if defined(CONFIG_PRE_SELF_DIAGNOSIS)
	lge_pre_self_diagnosis((char *) "modem", 3, (char *) "modem failed", (char *) reason, 20001);
#endif

/* [START] [email protected], SSR FEATURE */
	strlcpy(ssr_noti, smem_reason, min(size, sizeof(ssr_noti)));
/* [END] [email protected], SSR FEATURE */
	smem_reason[0] = '\0';
	wmb();
}
static irqreturn_t modem_err_fatal_intr_handler(int irq, void *dev_id)
{
	struct modem_data *drv = subsys_to_drv(dev_id);

	/* Ignore if we're the one that set the force stop GPIO */
	if (drv->crash_shutdown)
		return IRQ_HANDLED;

	if (check_modem_reset(drv) == 0)
		return IRQ_HANDLED;

	pr_err("Fatal error on the modem.\n");
#if defined(CONFIG_PRE_SELF_DIAGNOSIS)
	lge_pre_self_diagnosis((char *) "modem", 2, (char *) "modem fatal", (char *) "_", 20000);
#endif
	subsys_set_crash_status(drv->subsys, true);
	restart_modem(drv);
	return IRQ_HANDLED;
}
static void modem_fatal_fn(struct work_struct *work)
{
	u32 modem_state;
	u32 panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
	u32 reset_smsm_states = SMSM_SYSTEM_REBOOT_USR | SMSM_SYSTEM_PWRDWN_USR;
	struct modem_data *drv;

	drv = container_of(work, struct modem_data, fatal_work);

	pr_err("Watchdog bite received from modem!\n");

	modem_state = smsm_get_state(SMSM_MODEM_STATE);
	pr_err("Modem SMSM state = 0x%x!\n", modem_state);
#if defined(CONFIG_PRE_SELF_DIAGNOSIS)
	lge_pre_self_diagnosis((char *) "modem",1,(char *) "Watchdog bite",(char *) "_", modem_state);
#endif

	if (modem_state == 0 || modem_state & panic_smsm_states) {
		subsystem_restart_dev(drv->subsys);
		enable_irq(drv->irq);
	} else if (modem_state & reset_smsm_states) {
		pr_err("User-invoked system reset/powerdown.");
		kernel_restart(NULL);
	} else {
		unsigned long timeout = msecs_to_jiffies(6000);

		pr_err("Modem AHB locked up. Trying to free up modem!\n");

		writel_relaxed(0x3, drv->cbase + MSS_MODEM_RESET);
		/*
		 * If we are still alive (allowing for the 5 second
		 * delayed-panic-reboot), the modem is either still wedged or
		 * SMSM didn't come through. Force panic in that case.
		 */
		schedule_delayed_work(&drv->unlock_work, timeout);
	}
}
static void modem_crash_shutdown(const struct subsys_desc *subsys)
{
	struct modem_data *drv = subsys_to_drv(subsys);
	drv->crash_shutdown = true;
#ifdef CONFIG_LGE_HANDLE_PANIC
	if (!subsys_get_crash_status(drv->subsys) && (lge_get_modem_panic() != 3)) {
#else
	if (!subsys_get_crash_status(drv->subsys)) {
#endif
		gpio_set_value(subsys->force_stop_gpio, 1);
		mdelay(STOP_ACK_TIMEOUT_MS);
	}
}

static int modem_ramdump(int enable, const struct subsys_desc *subsys)
{
	struct modem_data *drv = subsys_to_drv(subsys);
	int ret;

	if (!enable)
		return 0;

	ret = pil_boot(&drv->q6->desc);
	if (ret)
		return ret;

	ret = pil_do_ramdump(&drv->mba->desc, drv->ramdump_dev);
	if (ret < 0)
		pr_err("Unable to dump modem fw memory (rc = %d).\n", ret);

	pil_shutdown(&drv->q6->desc);
	return ret;
}

static int adsp_state_notifier_fn(struct notifier_block *this,
				unsigned long code, void *ss_handle)
{
	int ret;
	ret = sysmon_send_event(SYSMON_SS_MODEM, "adsp", code);
	if (ret < 0)
		pr_err("%s: sysmon_send_event failed (%d).", __func__, ret);
	return NOTIFY_DONE;
}

static struct notifier_block adsp_state_notifier_block = {
	.notifier_call = adsp_state_notifier_fn,
};

static irqreturn_t modem_wdog_bite_intr_handler(int irq, void *dev_id)
{
	struct modem_data *drv = subsys_to_drv(dev_id);
	if (drv->ignore_errors)
		return IRQ_HANDLED;

	/* START : subsys_modem_restart : testmode */
	if (ignore_errors_by_subsys_modem_restart) {
		pr_err("IGNORE watchdog bite received from modem software!\n");
		return IRQ_HANDLED;
	}
	/* END : subsys_modem_restart : testmode */

	if (check_modem_reset(drv) == 0) {
		pr_err("IGNORE watchdog bite received from modem software during check_modem_reset!\n");
		return IRQ_HANDLED;
	}

	pr_err("Watchdog bite received from modem software!\n");
#if defined(CONFIG_PRE_SELF_DIAGNOSIS)
	lge_pre_self_diagnosis((char *) "modem", 2, (char *) "Watchdog bite Intr", (char *) "_", 20000);
#endif

	subsys_set_crash_status(drv->subsys, true);
	restart_modem(drv);
	return IRQ_HANDLED;
}

static int mss_start(const struct subsys_desc *desc)
{
	int ret;
	struct modem_data *drv = subsys_to_drv(desc);

	if (desc->is_not_loadable)
		return 0;

	INIT_COMPLETION(drv->stop_ack);
	ret = pil_boot(&drv->q6->desc);
	if (ret)
		return ret;
	ret = pil_boot(&drv->mba->desc);
	if (ret)
		pil_shutdown(&drv->q6->desc);
	return ret;
}