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

Commit 861b7df6 authored by Mukesh Kumar Savaliya's avatar Mukesh Kumar Savaliya Committed by Gerrit - the friendly Code Review server
Browse files

serial: msm_serial_hs: Allow system suspend when no client is active



In some cases, attempt to system resume imbalances the PM usage_count
which completely disables runtime PM callbacks of the device and suspend
doesn't happen.

Allow device to enter suspend through system PM when such condition met
and in addition do not suspend manually if runtime PM is disabled, let
auto suspend takes care of it.

Change-Id: I73df5804d47f551bfee97f43dbe772ee3774b399
Signed-off-by: default avatarMukesh Kumar Savaliya <msavaliy@codeaurora.org>
parent ea5fb4f7
Loading
Loading
Loading
Loading
+41 −30
Original line number Diff line number Diff line
@@ -258,6 +258,7 @@ struct msm_hs_port {
	atomic_t client_count;
	bool obs; /* out of band sleep flag */
	atomic_t client_req_state;
	int sys_suspend_noirq_cnt;
	void *ipc_msm_hs_log_ctxt;
	void *ipc_msm_hs_pwr_ctxt;
	int ipc_debug_mask;
@@ -395,8 +396,6 @@ static void msm_hs_resource_unvote(struct msm_hs_port *msm_uport)
{
	struct uart_port *uport = &(msm_uport->uport);
	int rc = atomic_read(&msm_uport->resource_count);
	struct msm_hs_tx *tx = &msm_uport->tx;
	struct msm_hs_rx *rx = &msm_uport->rx;

	MSM_HS_DBG("%s(): power usage count %d", __func__, rc);
	if (rc <= 0) {
@@ -405,15 +404,8 @@ static void msm_hs_resource_unvote(struct msm_hs_port *msm_uport)
		return;
	}
	atomic_dec(&msm_uport->resource_count);

	if (pm_runtime_enabled(uport->dev)) {
	pm_runtime_mark_last_busy(uport->dev);
	pm_runtime_put_autosuspend(uport->dev);
	} else {
		MSM_HS_DBG("%s():tx.flush:%d,in_flight:%d,rx.flush:%d\n",
		__func__, tx->flush, tx->dma_in_flight, rx->flush);
		msm_hs_pm_suspend(uport->dev);
	}
}

 /* Vote for resources before accessing them */
@@ -1390,8 +1382,9 @@ static void msm_hs_disconnect_rx(struct uart_port *uport)
	if (msm_uport->rx.flush == FLUSH_NONE)
		msm_uport->rx.flush = FLUSH_STOP;

	if (sps_is_pipe_empty(sps_pipe_handle, &prod_empty)) {
		MSM_HS_WARN("%s():Pipe Not Empty, ret=%d, flush=%d\n",
	if (!sps_is_pipe_empty(sps_pipe_handle, &prod_empty)) {
		if (prod_empty == false)
		MSM_HS_WARN("%s():Pipe Not Empty, prod=%d, flush=%d\n",
			__func__, prod_empty, msm_uport->rx.flush);
	}
	disconnect_rx_endpoint(msm_uport);
@@ -3295,6 +3288,7 @@ static int msm_hs_pm_resume(struct device *dev)
	LOG_USR_MSG(msm_uport->ipc_msm_hs_pwr_ctxt,
		"%s:PM State:Active client_count %d\n", __func__, client_count);
exit_pm_resume:
	msm_uport->sys_suspend_noirq_cnt = 0;
	mutex_unlock(&msm_uport->mtx);
	return ret;
}
@@ -3304,14 +3298,11 @@ static int msm_hs_pm_sys_suspend_noirq(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
	enum msm_hs_pm_state prev_pwr_state;
	int clk_cnt, client_count, ret = 0;

	if (IS_ERR_OR_NULL(msm_uport))
		return -ENODEV;

	mutex_lock(&msm_uport->mtx);

	/*
	 * If there is an active clk request or an impending userspace request
	 * fail the suspend callback.
@@ -3319,19 +3310,40 @@ static int msm_hs_pm_sys_suspend_noirq(struct device *dev)
	clk_cnt = atomic_read(&msm_uport->resource_count);
	client_count = atomic_read(&msm_uport->client_count);
	if (msm_uport->pm_state == MSM_HS_PM_ACTIVE) {
		MSM_HS_WARN("%s:Fail Suspend.clk_cnt:%d,clnt_count:%d\n",
				 __func__, clk_cnt, client_count);
		if (clk_cnt == 0 && client_count == 0)
			msm_uport->sys_suspend_noirq_cnt++;
		/*Serve force suspend post autosuspend timer expires
		 */
		if (msm_uport->sys_suspend_noirq_cnt >= 2) {
			msm_uport->pm_state = MSM_HS_PM_SYS_SUSPENDED;
			msm_uport->sys_suspend_noirq_cnt = 0;
			mutex_unlock(&msm_uport->mtx);

			msm_hs_pm_suspend(dev);
			/*
			 * Synchronize RT-pm and system-pm, RT-PM thinks that
			 * we are active. The three calls below let the RT-PM
			 * know that we are suspended already without calling
			 * suspend callback
			 */
			pm_runtime_disable(dev);
			pm_runtime_set_suspended(dev);
			pm_runtime_enable(dev);

			/*To Balance out exit time Mutex unlock */
			mutex_lock(&msm_uport->mtx);
		} else {
			ret = -EBUSY;
		goto exit_suspend_noirq;
		}

	prev_pwr_state = msm_uport->pm_state;
	msm_uport->pm_state = MSM_HS_PM_SYS_SUSPENDED;
	LOG_USR_MSG(msm_uport->ipc_msm_hs_pwr_ctxt,
		"%s:PM State:Sys-Suspended client_count %d\n", __func__,
								client_count);
exit_suspend_noirq:
	}
	mutex_unlock(&msm_uport->mtx);
	if (ret)
		MSM_HS_WARN("%s:Fail Suspend.clk_cnt:%d,clnt_count:%d\n",
			__func__, clk_cnt, client_count);
	else
		LOG_USR_MSG(msm_uport->ipc_msm_hs_pwr_ctxt,
			"%s:PM State:Sys-Suspended client_count %d\n",
			__func__, client_count);
	return ret;
};

@@ -3817,11 +3829,10 @@ static void msm_hs_shutdown(struct uart_port *uport)
	if (atomic_read(&msm_uport->client_count)) {
		MSM_HS_WARN("%s: Client vote on, forcing to 0\n", __func__);
		atomic_set(&msm_uport->client_count, 0);
		LOG_USR_MSG(msm_uport->ipc_msm_hs_pwr_ctxt,
			"%s: Client_Count 0\n", __func__);
	}
	msm_hs_unconfig_uart_gpios(uport);
	MSM_HS_INFO("%s:UART port closed successfully\n", __func__);
	LOG_USR_MSG(msm_uport->ipc_msm_hs_pwr_ctxt,
		"%s:UART port closed, Client_Count 0\n", __func__);
}

static void __exit msm_serial_hs_exit(void)