serial: omap: Fix missing pm_runtime_resume handling by simplifying code
PATCH 1/1 serial: omap: Fix missing pm_runtime_resume handling by simplifying code
The lack of pm_runtime_resume handling for the device state leads into device wake-up interrupts not working after a while for runtime PM.
Also, serial-omap is confused about the use of device_may_wakeup. The checks for device_may_wakeup should only be done for suspend and resume, not for pm_runtime_suspend and pm_runtime_resume. The wake-up events for PM runtime should always be enabled.
The lack of pm_runtime_resume handling leads into device wake-up interrupts not working after a while for runtime PM.
Rather than try to patch over the issue of adding complex tests to the pm_runtime_resume, let's fix the issues properly:
1. Make serial_omap_enable_wakeup deal with all internal PM state handling so we don't need to test for up->wakeups_enabled elsewhere.
Later on once omap3 boots in device tree only mode we can also remove the up->wakeups_enabled flag and rely on the wake-up interrupt enable/disable state alone.
2. Do the device_may_wakeup checks in suspend and resume only, for runtime PM the wake-up events need to be always enabled.
3. Finally just call serial_omap_enable_wakeup and make sure we call it also in pm_runtime_resume.
4. Note that we also have to use disable_irq_nosync as serial_omap_irq calls pm_runtime_get_sync.
drivers/tty/serial/omap-serial.c +17 -12
@@ -225,14 +225,19 @@ static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up,if (enable)enable_irq (up->wakeirq);else -disable_irq (up->wakeirq); +disable_irq_nosync (up->wakeirq); }static void serial_omap_enable_wakeup (struct uart_omap_port *up,bool enable) {struct omap_uart_port_info *pdata =dev_get_platdata (up->dev); +if (enable == up->wakeups_enabled) +return ; +serial_omap_enable_wakeirq (up, enable); + up->wakeups_enabled = enable; +if (!pdata || !pdata->enable_wakeup)return ;
@@ -1495,6 +1500,11 @@ static int serial_omap_suspend(struct device *dev)uart_suspend_port (&serial_omap_reg, &up->port);flush_work (&up->qos_work); +if (device_may_wakeup (dev)) +serial_omap_enable_wakeup (up, true); +else +serial_omap_enable_wakeup (up, false); +return 0 ; }
@@ -1502,6 +1512,9 @@ static int serial_omap_resume(struct device *dev) {struct uart_omap_port *up =dev_get_drvdata (dev); +if (device_may_wakeup (dev)) +serial_omap_enable_wakeup (up, false); +uart_resume_port (&serial_omap_reg, &up->port);return 0 ;
@@ -1877,17 +1890,7 @@ static int serial_omap_runtime_suspend(struct device *dev) up->context_loss_cnt =serial_omap_get_context_loss_count (up); -if (device_may_wakeup (dev)) { -if (!up->wakeups_enabled) { -serial_omap_enable_wakeup (up, true); - up->wakeups_enabled = true; - } - }else { -if (up->wakeups_enabled) { -serial_omap_enable_wakeup (up, false); - up->wakeups_enabled = false; - } - } +serial_omap_enable_wakeup (up, true); up->latency =PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE ;schedule_work (&up->qos_work);
@@ -1901,6 +1904,8 @@ static int serial_omap_runtime_resume(struct device *dev)int loss_cnt =serial_omap_get_context_loss_count (up); +serial_omap_enable_wakeup (up, false); +if (loss_cnt <0 ) {dev_dbg (dev,"serial_omap_get_context_loss_count failed : %d\n" , loss_cnt);
Quoted 37 lines · Tony Lindgren
The lack of
pm_runtime_resumehandling for the device state leads into device wake-up interrupts not working after a while for runtime PM.Also, serial-omap is confused about the use of
device_may_wakeup. The checks fordevice_may_wakeupshould only be done for suspend and resume, not forpm_runtime_suspendandpm_runtime_resume. The wake-up events for PM runtime should always be enabled.The lack of
pm_runtime_resumehandling leads into device wake-up interrupts not working after a while for runtime PM.Rather than try to patch over the issue of adding complex tests to the
pm_runtime_resume, let's fix the issues properly:1. Make
serial_omap_enable_wakeupdeal with all internal PM state handling so we don't need to test forup->wakeups_enabledelsewhere.Later on once omap3 boots in device tree only mode we can also remove the
up->wakeups_enabledflag and rely on the wake-up interrupt enable/disable state alone.2. Do the
device_may_wakeupchecks in suspend and resume only, for runtime PM the wake-up events need to be always enabled.3. Finally just call
serial_omap_enable_wakeupand make sure we call it also inpm_runtime_resume.4. Note that we also have to use
disable_irq_nosyncasserial_omap_irqcallspm_runtime_get_sync.Fixes 2a0b965cfb6e (serial: omap: Add support for optional wake-up)Cc [email protected] # v3.13+Signed-off-by Tony Lindgren <[email protected]>
drivers/tty/serial/omap-serial.c static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, · line 228
Quoted 5 lines
drivers/tty/serial/omap-serial.c +1
-1@@ -225,14 +225,19 @@ static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up,if (enable)enable_irq (up->wakeirq);else -disable_irq (up->wakeirq); +disable_irq_nosync (up->wakeirq);
looks to me liket his should be a separate fix of its own...
drivers/tty/serial/omap-serial.c static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, · line 236
Quoted 6 lines
drivers/tty/serial/omap-serial.c +2
-0static void serial_omap_enable_wakeup (struct uart_omap_port *up,bool enable) {struct omap_uart_port_info *pdata =dev_get_platdata (up->dev); +if (enable == up->wakeups_enabled) +return ;
is there any case where you would call this function twice with the same argument ?
Quoted 57 lines
drivers/tty/serial/omap-serial.c +14
-11+serial_omap_enable_wakeirq (up, enable); + up->wakeups_enabled = enable; +if (!pdata || !pdata->enable_wakeup)return ;@@ -1495,6 +1500,11 @@ static int serial_omap_suspend(struct device *dev)uart_suspend_port (&serial_omap_reg, &up->port);flush_work (&up->qos_work); +if (device_may_wakeup (dev)) +serial_omap_enable_wakeup (up, true); +else +serial_omap_enable_wakeup (up, false); +return 0 ; }@@ -1502,6 +1512,9 @@ static int serial_omap_resume(struct device *dev) {struct uart_omap_port *up =dev_get_drvdata (dev); +if (device_may_wakeup (dev)) +serial_omap_enable_wakeup (up, false); +uart_resume_port (&serial_omap_reg, &up->port);return 0 ;@@ -1877,17 +1890,7 @@ static int serial_omap_runtime_suspend(struct device *dev) up->context_loss_cnt =serial_omap_get_context_loss_count (up); -if (device_may_wakeup (dev)) { -if (!up->wakeups_enabled) { -serial_omap_enable_wakeup (up, true); - up->wakeups_enabled = true; - } - }else { -if (up->wakeups_enabled) { -serial_omap_enable_wakeup (up, false); - up->wakeups_enabled = false; - } - } +serial_omap_enable_wakeup (up, true); up->latency =PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE ;schedule_work (&up->qos_work);@@ -1901,6 +1904,8 @@ static int serial_omap_runtime_resume(struct device *dev)int loss_cnt =serial_omap_get_context_loss_count (up); +serial_omap_enable_wakeup (up, false); +if (loss_cnt <0 ) {dev_dbg (dev,"serial_omap_get_context_loss_count failed : %d\n" , loss_cnt);
Signature · 1 line
balbi
Quoted 35 lines · Felipe Balbi
Quoted 34 lines · Tony Lindgren
The lack of
pm_runtime_resumehandling for the device state leads into device wake-up interrupts not working after a while for runtime PM.Also, serial-omap is confused about the use of
device_may_wakeup. The checks fordevice_may_wakeupshould only be done for suspend and resume, not forpm_runtime_suspendandpm_runtime_resume. The wake-up events for PM runtime should always be enabled.The lack of
pm_runtime_resumehandling leads into device wake-up interrupts not working after a while for runtime PM.Rather than try to patch over the issue of adding complex tests to the
pm_runtime_resume, let's fix the issues properly:1. Make
serial_omap_enable_wakeupdeal with all internal PM state handling so we don't need to test forup->wakeups_enabledelsewhere.Later on once omap3 boots in device tree only mode we can also remove the
up->wakeups_enabledflag and rely on the wake-up interrupt enable/disable state alone.2. Do the
device_may_wakeupchecks in suspend and resume only, for runtime PM the wake-up events need to be always enabled.3. Finally just call
serial_omap_enable_wakeupand make sure we call it also inpm_runtime_resume.4. Note that we also have to use
disable_irq_nosyncasserial_omap_irqcallspm_runtime_get_sync.Fixes 2a0b965cfb6e (serial: omap: Add support for optional wake-up)Cc [email protected] # v3.13+Signed-off-by Tony Lindgren <[email protected]>
Quoted 10 lines
drivers/tty/serial/omap-serial.c static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, · line 228
Quoted 8 lines
drivers/tty/serial/omap-serial.c +1
-1@@ -225,14 +225,19 @@ static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up,if (enable)enable_irq (up->wakeirq);else -disable_irq (up->wakeirq); +disable_irq_nosync (up->wakeirq);looks to me liket his should be a separate fix of its own...
I don't think fixing disable_irq_nosync here is not needed without fixing the rest. We're currently never calling serial_omap_enable_wakeup from the runtime PM resume path.
So serial_omap_enable_wakeirq(up, 0) would only get called in the case of device_may_wakeup disabled from serial_omap_runtime_suspend, which is not called from the interrupt context.
Quoted 9 lines
drivers/tty/serial/omap-serial.c static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, · line 236
Quoted 6 lines
drivers/tty/serial/omap-serial.c +2
-0static void serial_omap_enable_wakeup (struct uart_omap_port *up,bool enable) {struct omap_uart_port_info *pdata =dev_get_platdata (up->dev); +if (enable == up->wakeups_enabled) +return ;is there any case where you would call this function twice with the same argument ?
Yes at least when serial-omap is runtime PM enabled and doing a suspend without device_may_wakeup being set.
I'd like to get rid of the wakeups_enabled, but it's probably safest to do that when ripping out the remaining context_loos_cnt stuff after we've made omap3 to boot also in device tree only mode.
Regards,
Tony
Quoted 27 lines · Tony Lindgren
The lack of
pm_runtime_resumehandling for the device state leads into device wake-up interrupts not working after a while for runtime PM.Also, serial-omap is confused about the use of
device_may_wakeup. The checks fordevice_may_wakeupshould only be done for suspend and resume, not forpm_runtime_suspendandpm_runtime_resume. The wake-up events for PM runtime should always be enabled.The lack of
pm_runtime_resumehandling leads into device wake-up interrupts not working after a while for runtime PM.Rather than try to patch over the issue of adding complex tests to the
pm_runtime_resume, let's fix the issues properly:1. Make
serial_omap_enable_wakeupdeal with all internal PM state handling so we don't need to test forup->wakeups_enabledelsewhere.Later on once omap3 boots in device tree only mode we can also remove the
up->wakeups_enabledflag and rely on the wake-up interrupt enable/disable state alone.2. Do the
device_may_wakeupchecks in suspend and resume only, for runtime PM the wake-up events need to be always enabled.3. Finally just call
serial_omap_enable_wakeupand make sure we call it also inpm_runtime_resume.
Quoted 6 lines
4. Note that we also have to use
disable_irq_nosyncasserial_omap_irqcallspm_runtime_get_sync.Fixes 2a0b965cfb6e (serial: omap: Add support for optional wake-up)Cc [email protected] # v3.13+Signed-off-by Tony Lindgren <[email protected]>
FWIW:
Signature · 1 line
balbi