Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 453c74ce authored by Sujeev Dias's avatar Sujeev Dias Committed by Gerrit - the friendly Code Review server
Browse files

mhi: core: Add support for PCIe linkdown abort



PCIe linkdown event can trigger anytime. During linkdown event
abort any work MHI host doing that require PCIE link.

CRs-Fixed: 2055975
Change-Id: Idba907c7977594dc08575e0020a7afa4868bc0e4
Signed-off-by: default avatarSujeev Dias <sdias@codeaurora.org>
parent 77eefb70
Loading
Loading
Loading
Loading
+14 −6
Original line number Original line Diff line number Diff line
@@ -439,7 +439,6 @@ void bhi_firmware_download(struct work_struct *work)
	struct bhi_ctxt_t *bhi_ctxt;
	struct bhi_ctxt_t *bhi_ctxt;
	struct bhie_mem_info mem_info;
	struct bhie_mem_info mem_info;
	int ret;
	int ret;
	long timeout;


	mhi_dev_ctxt = container_of(work, struct mhi_device_ctxt,
	mhi_dev_ctxt = container_of(work, struct mhi_device_ctxt,
				    bhi_ctxt.fw_load_work);
				    bhi_ctxt.fw_load_work);
@@ -448,7 +447,14 @@ void bhi_firmware_download(struct work_struct *work)
	mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Enter\n");
	mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Enter\n");


	wait_event_interruptible(*mhi_dev_ctxt->mhi_ev_wq.bhi_event,
	wait_event_interruptible(*mhi_dev_ctxt->mhi_ev_wq.bhi_event,
			mhi_dev_ctxt->mhi_state == MHI_STATE_BHI);
		mhi_dev_ctxt->mhi_state == MHI_STATE_BHI ||
		mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT);
	if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT ||
	    mhi_dev_ctxt->mhi_state != MHI_STATE_BHI) {
		mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
			"MHI is not in valid state for firmware download\n");
		return;
	}


	/* PBL image is the first segment in firmware vector table */
	/* PBL image is the first segment in firmware vector table */
	mem_info = *bhi_ctxt->fw_table.bhie_mem_info;
	mem_info = *bhi_ctxt->fw_table.bhie_mem_info;
@@ -462,10 +468,12 @@ void bhi_firmware_download(struct work_struct *work)
	mhi_init_state_transition(mhi_dev_ctxt,
	mhi_init_state_transition(mhi_dev_ctxt,
				  STATE_TRANSITION_RESET);
				  STATE_TRANSITION_RESET);


	timeout = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.bhi_event,
	wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.bhi_event,
				mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_BHIE,
		mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_BHIE ||
		mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
		msecs_to_jiffies(bhi_ctxt->poll_timeout));
		msecs_to_jiffies(bhi_ctxt->poll_timeout));
	if (!timeout) {
	if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT ||
	    mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_BHIE) {
		mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
		mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
			"Failed to Enter EXEC_ENV_BHIE\n");
			"Failed to Enter EXEC_ENV_BHIE\n");
		return;
		return;
+49 −17
Original line number Original line Diff line number Diff line
@@ -98,11 +98,13 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
	read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
	read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
	r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event,
	r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event,
		mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
		mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
			       mhi_dev_ctxt->mhi_state == MHI_STATE_M1,
		mhi_dev_ctxt->mhi_state == MHI_STATE_M1 ||
		mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
		msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
		msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
	if (!r) {
	if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) {
		mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
		mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
			"Failed to get M0||M1 event, timeout, current state:%s\n",
			"Failed to get M0||M1 event or LD pm_state:0x%x state:%s\n",
			mhi_dev_ctxt->mhi_pm_state,
			TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
			TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
		return -EIO;
		return -EIO;
	}
	}
@@ -122,9 +124,10 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
	write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
	write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
	mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Waiting for M3 completion.\n");
	mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Waiting for M3 completion.\n");
	r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m3_event,
	r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m3_event,
			       mhi_dev_ctxt->mhi_state == MHI_STATE_M3,
		mhi_dev_ctxt->mhi_state == MHI_STATE_M3 ||
		mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
		msecs_to_jiffies(MHI_MAX_SUSPEND_TIMEOUT));
		msecs_to_jiffies(MHI_MAX_SUSPEND_TIMEOUT));
	if (!r) {
	if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) {
		mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
		mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
			"Failed to get M3 event, timeout, current state:%s\n",
			"Failed to get M3 event, timeout, current state:%s\n",
			TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
			TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
@@ -159,11 +162,12 @@ static int mhi_pm_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt)
	write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
	write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
	r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event,
	r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event,
		mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
		mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
			       mhi_dev_ctxt->mhi_state == MHI_STATE_M1,
		mhi_dev_ctxt->mhi_state == MHI_STATE_M1 ||
		mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
		msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
		msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
	if (!r) {
	if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) {
		mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
		mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
			"Failed to get M0 event, timeout\n");
			"Failed to get M0 event, timeout or LD\n");
		r = -EIO;
		r = -EIO;
	} else
	} else
		r = 0;
		r = 0;
@@ -295,13 +299,16 @@ static int mhi_pm_slave_mode_power_on(struct mhi_device_ctxt *mhi_dev_ctxt)
	mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false);
	mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false);
	read_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
	read_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);


	ret_val = wait_for_completion_timeout(&mhi_dev_ctxt->cmd_complete,
	wait_for_completion_timeout(&mhi_dev_ctxt->cmd_complete,
				    msecs_to_jiffies(timeout));
				    msecs_to_jiffies(timeout));
	if (!ret_val || mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_AMSS)
	if (mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_AMSS)
		ret_val = -EIO;
		ret_val = -EIO;
	else
	else
		ret_val = 0;
		ret_val = 0;


	/* wait for firmware download to complete */
	flush_work(&mhi_dev_ctxt->bhi_ctxt.fw_load_work);

	if (ret_val) {
	if (ret_val) {
		read_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
		read_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
		mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
		mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
@@ -563,9 +570,28 @@ int mhi_pm_control_device(struct mhi_device *mhi_device,
	case MHI_DEV_CTRL_RDDM:
	case MHI_DEV_CTRL_RDDM:
		return bhi_rddm(mhi_dev_ctxt, false);
		return bhi_rddm(mhi_dev_ctxt, false);
	case MHI_DEV_CTRL_DE_INIT:
	case MHI_DEV_CTRL_DE_INIT:
		if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE)
		if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE) {
			enum MHI_PM_STATE cur_state;
			/*
			 * If bus master calls DE_INIT before calling POWER_OFF
			 * means a critical failure occurred during POWER_ON
			 * state transition and external PCIe device may not
			 * respond to host.  Force PM state to PCIe linkdown
			 * state prior to starting shutdown process to avoid
			 * accessing PCIe link.
			 */
			write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
			cur_state = mhi_tryset_pm_state(mhi_dev_ctxt,
						MHI_PM_LD_ERR_FATAL_DETECT);
			write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
			if (unlikely(cur_state != MHI_PM_LD_ERR_FATAL_DETECT)) {
				mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
					"Failed to transition to state 0x%x from 0x%x\n",
					MHI_PM_LD_ERR_FATAL_DETECT, cur_state);
			}
			process_disable_transition(MHI_PM_SHUTDOWN_PROCESS,
			process_disable_transition(MHI_PM_SHUTDOWN_PROCESS,
						   mhi_dev_ctxt);
						   mhi_dev_ctxt);
		}
		bhi_exit(mhi_dev_ctxt);
		bhi_exit(mhi_dev_ctxt);
		break;
		break;
	case MHI_DEV_CTRL_NOTIFY_LINK_ERROR:
	case MHI_DEV_CTRL_NOTIFY_LINK_ERROR:
@@ -580,6 +606,12 @@ int mhi_pm_control_device(struct mhi_device *mhi_device,
			mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
			mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
				"Failed to transition to state 0x%x from 0x%x\n",
				"Failed to transition to state 0x%x from 0x%x\n",
				MHI_PM_LD_ERR_FATAL_DETECT, cur_state);
				MHI_PM_LD_ERR_FATAL_DETECT, cur_state);

		/* wake up all threads that's waiting for state change events */
		complete(&mhi_dev_ctxt->cmd_complete);
		wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.bhi_event);
		wake_up(mhi_dev_ctxt->mhi_ev_wq.m0_event);
		wake_up(mhi_dev_ctxt->mhi_ev_wq.m3_event);
		break;
		break;
	}
	}
	default:
	default:
+3 −2
Original line number Original line Diff line number Diff line
@@ -147,7 +147,8 @@ void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt,
 *     M1 -> M3_ENTER --> M3
 *     M1 -> M3_ENTER --> M3
 * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR
 * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR
 * L2: SHUTDOWN_PROCESS -> DISABLE -> SSR_PENDING (via SSR Notification only)
 * L2: SHUTDOWN_PROCESS -> DISABLE -> SSR_PENDING (via SSR Notification only)
 * L3: LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS
 * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT
 *     LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS
 */
 */
static const struct mhi_pm_transitions const mhi_state_transitions[] = {
static const struct mhi_pm_transitions const mhi_state_transitions[] = {
	/* L0 States */
	/* L0 States */
@@ -216,7 +217,7 @@ static const struct mhi_pm_transitions const mhi_state_transitions[] = {
	/* L3 States */
	/* L3 States */
	{
	{
		MHI_PM_LD_ERR_FATAL_DETECT,
		MHI_PM_LD_ERR_FATAL_DETECT,
		MHI_PM_SHUTDOWN_PROCESS
		MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_PROCESS
	},
	},
	/* From SSR notification only */
	/* From SSR notification only */
	{
	{