msm_serial_hs: Change resource voting and system suspend logic
As part of the resource voting, both the resource_vote and unvote functions call the toggle_wakeup_interrupt() function which toggles the state of the wakeup irq unconditionally. This can cause issues in adverse scenarios. Instead split this out into exclusive enable and disable wakeup interrupt functions to be called during the resource unvote and vote respectively. Also don't make resource votes in the wakeup isr, the wakeup isr injects a pre-determined byte into the tty flip buffer and doesn't access the core or setup any transactions and hence doesn't need to vote for resources. The driver has registered for the noirq system suspend/resume callbacks. When executing these callbacks, don't rely on the runtime framework to check the device's current runtime state before deciding whether to allow system suspend or not as the runtime framework is disabled at this point. Instead rely on the power state that the driver maintains internally. Change-Id: I0e5d6b8a8a69efc2d9c65dc1edc85f13cbc94fc3 Signed-off-by: Girish Mahadevan <girishm@codeaurora.org>
This commit is contained in:
parent
9de853543c
commit
a674be9d15
1 changed files with 25 additions and 15 deletions
|
@ -353,6 +353,7 @@ static int msm_hs_clk_bus_vote(struct msm_hs_port *msm_uport)
|
||||||
__func__, rc);
|
__func__, rc);
|
||||||
goto core_unprepare;
|
goto core_unprepare;
|
||||||
}
|
}
|
||||||
|
atomic_inc(&msm_uport->clk_count);
|
||||||
MSM_HS_DBG("%s: Clock ON successful\n", __func__);
|
MSM_HS_DBG("%s: Clock ON successful\n", __func__);
|
||||||
return rc;
|
return rc;
|
||||||
core_unprepare:
|
core_unprepare:
|
||||||
|
@ -373,6 +374,7 @@ static void msm_hs_clk_bus_unvote(struct msm_hs_port *msm_uport)
|
||||||
if (msm_uport->pclk)
|
if (msm_uport->pclk)
|
||||||
clk_disable_unprepare(msm_uport->pclk);
|
clk_disable_unprepare(msm_uport->pclk);
|
||||||
msm_hs_bus_voting(msm_uport, BUS_RESET);
|
msm_hs_bus_voting(msm_uport, BUS_RESET);
|
||||||
|
atomic_dec(&msm_uport->clk_count);
|
||||||
MSM_HS_DBG("%s: Clock OFF successful\n", __func__);
|
MSM_HS_DBG("%s: Clock OFF successful\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +390,6 @@ static void msm_hs_resource_unvote(struct msm_hs_port *msm_uport)
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
atomic_dec(&msm_uport->clk_count);
|
|
||||||
pm_runtime_mark_last_busy(uport->dev);
|
pm_runtime_mark_last_busy(uport->dev);
|
||||||
pm_runtime_put_autosuspend(uport->dev);
|
pm_runtime_put_autosuspend(uport->dev);
|
||||||
}
|
}
|
||||||
|
@ -404,8 +405,6 @@ static void msm_hs_resource_vote(struct msm_hs_port *msm_uport)
|
||||||
__func__, uport->dev, ret);
|
__func__, uport->dev, ret);
|
||||||
msm_hs_pm_resume(uport->dev);
|
msm_hs_pm_resume(uport->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_inc(&msm_uport->clk_count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the uport line number matches with user id stored in pdata.
|
/* Check if the uport line number matches with user id stored in pdata.
|
||||||
|
@ -2186,7 +2185,7 @@ static struct msm_hs_port *msm_hs_get_hs_port(int port_index)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void toggle_wakeup_interrupt(struct msm_hs_port *msm_uport)
|
void enable_wakeup_interrupt(struct msm_hs_port *msm_uport)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct uart_port *uport = &(msm_uport->uport);
|
struct uart_port *uport = &(msm_uport->uport);
|
||||||
|
@ -2197,7 +2196,6 @@ void toggle_wakeup_interrupt(struct msm_hs_port *msm_uport)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(msm_uport->wakeup.enabled)) {
|
if (!(msm_uport->wakeup.enabled)) {
|
||||||
MSM_HS_DBG("%s(): Enable Wakeup IRQ", __func__);
|
|
||||||
enable_irq(msm_uport->wakeup.irq);
|
enable_irq(msm_uport->wakeup.irq);
|
||||||
disable_irq(uport->irq);
|
disable_irq(uport->irq);
|
||||||
spin_lock_irqsave(&uport->lock, flags);
|
spin_lock_irqsave(&uport->lock, flags);
|
||||||
|
@ -2205,12 +2203,28 @@ void toggle_wakeup_interrupt(struct msm_hs_port *msm_uport)
|
||||||
msm_uport->wakeup.enabled = true;
|
msm_uport->wakeup.enabled = true;
|
||||||
spin_unlock_irqrestore(&uport->lock, flags);
|
spin_unlock_irqrestore(&uport->lock, flags);
|
||||||
} else {
|
} else {
|
||||||
|
MSM_HS_WARN("%s:Wake up IRQ already enabled", __func__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable_wakeup_interrupt(struct msm_hs_port *msm_uport)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct uart_port *uport = &(msm_uport->uport);
|
||||||
|
|
||||||
|
if (!is_use_low_power_wakeup(msm_uport))
|
||||||
|
return;
|
||||||
|
if (msm_uport->wakeup.freed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (msm_uport->wakeup.enabled) {
|
||||||
disable_irq_nosync(msm_uport->wakeup.irq);
|
disable_irq_nosync(msm_uport->wakeup.irq);
|
||||||
enable_irq(uport->irq);
|
enable_irq(uport->irq);
|
||||||
spin_lock_irqsave(&uport->lock, flags);
|
spin_lock_irqsave(&uport->lock, flags);
|
||||||
msm_uport->wakeup.enabled = false;
|
msm_uport->wakeup.enabled = false;
|
||||||
spin_unlock_irqrestore(&uport->lock, flags);
|
spin_unlock_irqrestore(&uport->lock, flags);
|
||||||
MSM_HS_DBG("%s(): Disable Wakeup IRQ", __func__);
|
} else {
|
||||||
|
MSM_HS_WARN("%s:Wake up IRQ already disabled", __func__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2342,7 +2356,6 @@ static irqreturn_t msm_hs_wakeup_isr(int irq, void *dev)
|
||||||
struct uart_port *uport = &msm_uport->uport;
|
struct uart_port *uport = &msm_uport->uport;
|
||||||
struct tty_struct *tty = NULL;
|
struct tty_struct *tty = NULL;
|
||||||
|
|
||||||
msm_hs_resource_vote(msm_uport);
|
|
||||||
spin_lock_irqsave(&uport->lock, flags);
|
spin_lock_irqsave(&uport->lock, flags);
|
||||||
|
|
||||||
MSM_HS_DBG("%s(): ignore %d\n", __func__,
|
MSM_HS_DBG("%s(): ignore %d\n", __func__,
|
||||||
|
@ -2368,7 +2381,6 @@ static irqreturn_t msm_hs_wakeup_isr(int irq, void *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&uport->lock, flags);
|
spin_unlock_irqrestore(&uport->lock, flags);
|
||||||
msm_hs_resource_unvote(msm_uport);
|
|
||||||
|
|
||||||
if (wakeup && msm_uport->wakeup.inject_rx)
|
if (wakeup && msm_uport->wakeup.inject_rx)
|
||||||
tty_flip_buffer_push(tty->port);
|
tty_flip_buffer_push(tty->port);
|
||||||
|
@ -3111,7 +3123,7 @@ static void msm_hs_pm_suspend(struct device *dev)
|
||||||
obs_manage_irq(msm_uport, false);
|
obs_manage_irq(msm_uport, false);
|
||||||
msm_hs_clk_bus_unvote(msm_uport);
|
msm_hs_clk_bus_unvote(msm_uport);
|
||||||
if (!atomic_read(&msm_uport->client_req_state))
|
if (!atomic_read(&msm_uport->client_req_state))
|
||||||
toggle_wakeup_interrupt(msm_uport);
|
enable_wakeup_interrupt(msm_uport);
|
||||||
MSM_HS_DBG("%s(): return suspend\n", __func__);
|
MSM_HS_DBG("%s(): return suspend\n", __func__);
|
||||||
mutex_unlock(&msm_uport->mtx);
|
mutex_unlock(&msm_uport->mtx);
|
||||||
return;
|
return;
|
||||||
|
@ -3133,7 +3145,7 @@ static int msm_hs_pm_resume(struct device *dev)
|
||||||
if (msm_uport->pm_state == MSM_HS_PM_ACTIVE)
|
if (msm_uport->pm_state == MSM_HS_PM_ACTIVE)
|
||||||
goto exit_pm_resume;
|
goto exit_pm_resume;
|
||||||
if (!atomic_read(&msm_uport->client_req_state))
|
if (!atomic_read(&msm_uport->client_req_state))
|
||||||
toggle_wakeup_interrupt(msm_uport);
|
disable_wakeup_interrupt(msm_uport);
|
||||||
msm_hs_clk_bus_vote(msm_uport);
|
msm_hs_clk_bus_vote(msm_uport);
|
||||||
obs_manage_irq(msm_uport, true);
|
obs_manage_irq(msm_uport, true);
|
||||||
msm_uport->pm_state = MSM_HS_PM_ACTIVE;
|
msm_uport->pm_state = MSM_HS_PM_ACTIVE;
|
||||||
|
@ -3176,11 +3188,9 @@ static int msm_hs_pm_sys_suspend_noirq(struct device *dev)
|
||||||
*/
|
*/
|
||||||
clk_cnt = atomic_read(&msm_uport->clk_count);
|
clk_cnt = atomic_read(&msm_uport->clk_count);
|
||||||
client_count = atomic_read(&msm_uport->client_count);
|
client_count = atomic_read(&msm_uport->client_count);
|
||||||
if (clk_cnt || (pm_runtime_enabled(dev) &&
|
if (msm_uport->pm_state == MSM_HS_PM_ACTIVE) {
|
||||||
!pm_runtime_suspended(dev))) {
|
MSM_HS_WARN("%s:Fail Suspend.clk_cnt:%d,clnt_count:%d\n",
|
||||||
MSM_HS_WARN("%s:Fail Suspend.clk_cnt:%d,clnt_count:%d,RPM:%d\n",
|
__func__, clk_cnt, client_count);
|
||||||
__func__, clk_cnt, client_count,
|
|
||||||
dev->power.runtime_status);
|
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto exit_suspend_noirq;
|
goto exit_suspend_noirq;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue