linux/arch/arm/plat-omap
Paul Walmsley b7c39a3f59 ARM: OMAP2+: omap_device: call all suspend, resume callbacks when OMAP_DEVICE_NO_IDLE_ON_SUSPEND is set
During system suspend, when OMAP_DEVICE_NO_IDLE_ON_SUSPEND is set on
an omap_device, call the corresponding driver's ->suspend() and
->suspend_noirq() callbacks (if present).  Similarly, during resume,
the driver's ->resume() and ->resume_noirq() callbacks must both be
called, if present.  (The previous code only called ->suspend_noirq()
and ->resume_noirq().)

If all of these callbacks aren't called, some important driver
suspend/resume code may not get executed.

In current mainline, the bug fixed by this patch is only a problem
under the following conditions:

- the kernel is running on an OMAP4

- an OMAP UART is used as a console

- the kernel command line parameter 'no_console_suspend' is specified

- and the system enters suspend ("echo mem > /sys/power/state").

Under this combined circumstance, the system cannot be awakened via
the serial port after commit be4b0281956c5cae4f63f31f11d07625a6988766c
("tty: serial: OMAP: block idle while the UART is transferring data in
PIO mode").  This is because the OMAP UART driver's ->suspend()
callback is never called.  The ->suspend() callback would have called
uart_suspend_port() which in turn would call enable_irq_wake().  Since
enable_irq_wake() isn't called for the UART's IRQ, check_wakeup_irqs()
would mask off the UART IRQ in the GIC.

On v3.3 kernels prior to the above commit, serial resume from suspend
presumably occurred via the PRCM interrupt.  The UART was in
smart-idle mode, so it was able to send a PRCM wakeup which in turn
would be converted into a PRCM interrupt to the GIC, waking up the
kernel.  But after the above commit, when the system is suspended in
the middle of a UART transmit, the UART IP block would be in no-idle
mode.  In no-idle mode, the UART won't generate wakeups to the PRCM
when incoming characters are received; only GIC interrupts.  But since
the UART driver's ->suspend() callback is never called,
uart_suspend_port() and enable_irq_wake() is never called; so the UART
interrupt is masked by check_wakeup_irqs() and the UART can't wake up
the MPU.

The remaining mechanism that could have awakened the system would have
been I/O chain wakeups.  These wouldn't be active because the console
UART's clocks are never disabled when no_console_suspend is used,
preventing the full chip from idling.  Also, current mainline doesn't
yet support full chip idle states for OMAP4, so I/O chain wakeups are
not enabled.

This patch is the result of a collaboration.  John Stultz
<johnstul@us.ibm.com> and Andy Green <andy.green@linaro.org> reported
the serial wakeup problem that led to the discovery of this problem.
Kevin Hilman <khilman@ti.com> narrowed the problem down to the use of
no_console_suspend.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: John Stultz <johnstul@us.ibm.com>
Cc: Andy Green <andy.green@linaro.org>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
2012-03-05 15:38:02 -08:00
..
include/plat ARM: OMAP: omap_device: remove omap_device_parent 2012-03-05 15:38:02 -08:00
clock.c arm: Add export.h to ARM specific files as required. 2011-10-31 19:30:50 -04:00
common.c ARM: OMAP: PM: Add support to allocate the memory for secure RAM 2011-12-08 11:29:00 -08:00
counter_32k.c ARM: OMAP: Remove plat/io.h by splitting it into mach/io.h and mach/hardware.h 2012-02-24 10:34:35 -08:00
debug-devices.c ARM: gpio: convert includes of mach/gpio.h and asm/gpio.h to linux/gpio.h 2011-08-08 14:27:41 +01:00
debug-leds.c ARM: gpio: convert includes of mach/gpio.h and asm/gpio.h to linux/gpio.h 2011-08-08 14:27:41 +01:00
devices.c ARM: Add arm_memblock_steal() to allocate memory away from the kernel 2012-01-13 15:02:35 +00:00
dma.c ARM: OMAP: Remove plat/io.h by splitting it into mach/io.h and mach/hardware.h 2012-02-24 10:34:35 -08:00
dmtimer.c ARM: OMAP: Remove plat/io.h by splitting it into mach/io.h and mach/hardware.h 2012-02-24 10:34:35 -08:00
fb.c Merge branch 'for-linus' of git://gitorious.org/linux-omap-dss2/linux 2010-10-26 10:02:39 -07:00
fb.h OMAP: plat-omap: Fix static function warnings 2010-10-08 10:12:38 -07:00
i2c.c ARM: OMAP: I2C: Fix omap_register_i2c_bus() return value on success 2011-11-04 17:41:07 -07:00
Kconfig ARM: GIC: Make MULTI_IRQ_HANDLER mandatory 2011-11-15 18:14:02 +00:00
mailbox.c arm: fix implicit module.h users by adding it to arch/arm as required. 2011-10-31 19:30:50 -04:00
Makefile ARM: OMAP: am33xx: Update common OMAP machine specific sources 2011-12-13 10:46:43 -08:00
mcbsp.c ARM: OMAP: mcbsp: Start generalize signal muxing functions 2011-09-26 17:49:07 -07:00
mux.c ARM: OMAP: Remove plat/io.h by splitting it into mach/io.h and mach/hardware.h 2012-02-24 10:34:35 -08:00
ocpi.c [ARM] Convert asm/io.h to linux/io.h 2008-09-06 12:10:45 +01:00
omap_device.c ARM: OMAP2+: omap_device: call all suspend, resume callbacks when OMAP_DEVICE_NO_IDLE_ON_SUSPEND is set 2012-03-05 15:38:02 -08:00
omap-pm-noop.c ARM: OMAP: omap_device: remove omap_device_parent 2012-03-05 15:38:02 -08:00
sram.c ARM: OMAP2+: Move most of plat/io.h into local iomap.h 2012-02-24 10:34:35 -08:00
sram.h OMAP: plat-omap: Fix static function warnings 2010-10-08 10:12:38 -07:00
usb.c ARM: OMAP: Remove plat/io.h by splitting it into mach/io.h and mach/hardware.h 2012-02-24 10:34:35 -08:00