From 0d8e2d0dad98a693bad88aea6876ac8b94ad95c6 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Wed, 24 Nov 2010 16:49:05 -0700 Subject: OMAP2+: PM/serial: hold console semaphore while OMAP UARTs are disabled The console semaphore must be held while the OMAP UART devices are disabled, lest a console write cause an ARM abort (and a kernel crash) when the underlying console device is inaccessible. These crashes only occur when the console is on one of the OMAP internal serial ports. While this problem has been latent in the PM idle loop for some time, the crash was not triggerable with an unmodified kernel until commit 6f251e9db1093c187addc309b5f2f7fe3efd2995 ("OMAP: UART: omap_device conversions, remove implicit 8520 assumptions"). After this patch, a console write often occurs after the console UART has been disabled in the idle loop, crashing the system. Several users have encountered this bug: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg38396.html http://www.mail-archive.com/linux-omap@vger.kernel.org/msg36602.html The same commit also introduced new code that disabled the UARTs during init, in omap_serial_init_port(). The kernel will also crash in this code when earlyconsole and extra debugging is enabled: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg36411.html The minimal fix for the -rc series is to hold the console semaphore while the OMAP UARTs are disabled. This is a somewhat overbroad fix, since the console may not be located on an OMAP UART, as is the case with the GPMC UART on Zoom3. While it is technically possible to determine which devices the console or earlyconsole is actually running on, it is not a trivial problem to solve, and the code to do so is not really appropriate for the -rc series. The right long-term fix is to ensure that no code outside of the OMAP serial driver can disable an OMAP UART. As I understand it, code to implement this is under development by TI. This patch is a collaboration between Paul Walmsley and Tony Lindgren . Thanks to Ming Lei and Pramod for their feedback on earlier versions of this patch. Signed-off-by: Paul Walmsley Signed-off-by: Tony Lindgren Acked-by: Kevin Hilman Cc: Ming Lei Cc: Pramod Cc: Thomas Petazzoni Cc: Jean Pihet Cc: Govindraj.R --- arch/arm/mach-omap2/pm34xx.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'arch/arm/mach-omap2/pm34xx.c') diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 75c0cd1..0ec8a04 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -385,6 +386,12 @@ void omap_sram_idle(void) omap3_enable_io_chain(); } + /* Block console output in case it is on one of the OMAP UARTs */ + if (per_next_state < PWRDM_POWER_ON || + core_next_state < PWRDM_POWER_ON) + if (try_acquire_console_sem()) + goto console_still_active; + /* PER */ if (per_next_state < PWRDM_POWER_ON) { omap_uart_prepare_idle(2); @@ -463,6 +470,9 @@ void omap_sram_idle(void) omap_uart_resume_idle(3); } + release_console_sem(); + +console_still_active: /* Disable IO-PAD and IO-CHAIN wakeup */ if (omap3_has_io_wakeup() && (per_next_state < PWRDM_POWER_ON || -- cgit v1.1 From e83df17f178360a8e7874441bca04a710c869e42 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Wed, 8 Dec 2010 22:40:40 +0000 Subject: OMAP2+: PM/serial: fix console semaphore acquire during suspend commit 0d8e2d0dad98a693bad88aea6876ac8b94ad95c6 (OMAP2+: PM/serial: hold console semaphore while OMAP UARTs are disabled) added use of the console semaphore to protect UARTs from being accessed after disabled during idle, but this causes problems in suspend. During suspend, the console semaphore is acquired by the console suspend method (console_suspend()) so the try_acquire_console_sem() will always fail and suspend will be aborted. To fix, introduce a check so the console semaphore is only attempted during idle, and not during suspend. Also use the same check so that the console semaphore is not prematurely released during resume. Thanks to Paul Walmsley for suggesting adding the same check during resume. Cc: Paul Walmsley Tested-by: Jean Pihet Tested-by: Paul Walmsley Signed-off-by: Kevin Hilman Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/pm34xx.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'arch/arm/mach-omap2/pm34xx.c') diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 0ec8a04..648b8c5 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -50,6 +50,19 @@ #include "sdrc.h" #include "control.h" +#ifdef CONFIG_SUSPEND +static suspend_state_t suspend_state = PM_SUSPEND_ON; +static inline bool is_suspending(void) +{ + return (suspend_state != PM_SUSPEND_ON); +} +#else +static inline bool is_suspending(void) +{ + return false; +} +#endif + /* Scratchpad offsets */ #define OMAP343X_TABLE_ADDRESS_OFFSET 0xc4 #define OMAP343X_TABLE_VALUE_OFFSET 0xc0 @@ -387,10 +400,11 @@ void omap_sram_idle(void) } /* Block console output in case it is on one of the OMAP UARTs */ - if (per_next_state < PWRDM_POWER_ON || - core_next_state < PWRDM_POWER_ON) - if (try_acquire_console_sem()) - goto console_still_active; + if (!is_suspending()) + if (per_next_state < PWRDM_POWER_ON || + core_next_state < PWRDM_POWER_ON) + if (try_acquire_console_sem()) + goto console_still_active; /* PER */ if (per_next_state < PWRDM_POWER_ON) { @@ -470,7 +484,8 @@ void omap_sram_idle(void) omap_uart_resume_idle(3); } - release_console_sem(); + if (!is_suspending()) + release_console_sem(); console_still_active: /* Disable IO-PAD and IO-CHAIN wakeup */ @@ -514,8 +529,6 @@ out: } #ifdef CONFIG_SUSPEND -static suspend_state_t suspend_state; - static int omap3_pm_prepare(void) { disable_hlt(); -- cgit v1.1