Skip to content

Commit

Permalink
OMAP3: Fixed crash bug with serial + suspend
Browse files Browse the repository at this point in the history
It was possible for an unhandled interrupt to occur if there was incoming
serial traffic during wakeup from suspend. This was caused by the code
in arch-arm/mach-omap2/serial.c keeping interrupt enabled all the time,
but not acking its interrupts. Applies on top of PM branch.

Use the PM begin/end hooks to ensure that the "serial idle" interrupts
are disabled during the suspend path.  Also, since begin/end hooks are
now used, use the suspend_state that is passed in the begin hook instead
of the enter hook as per the platform_suspend_ops docs.

Signed-off-by: Tero Kristo <tero.kristo@nokia.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
  • Loading branch information
Tero Kristo authored and Kevin Hilman committed Aug 5, 2009
1 parent 4789998 commit 2466211
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 2 deletions.
23 changes: 21 additions & 2 deletions arch/arm/mach-omap2/pm34xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,8 @@ static void omap3_pm_idle(void)
}

#ifdef CONFIG_SUSPEND
static suspend_state_t suspend_state;

static int omap3_pm_prepare(void)
{
disable_hlt();
Expand Down Expand Up @@ -342,11 +344,11 @@ static int omap3_pm_suspend(void)
return ret;
}

static int omap3_pm_enter(suspend_state_t state)
static int omap3_pm_enter(suspend_state_t unused)
{
int ret = 0;

switch (state) {
switch (suspend_state) {
case PM_SUSPEND_STANDBY:
case PM_SUSPEND_MEM:
ret = omap3_pm_suspend();
Expand All @@ -363,7 +365,24 @@ static void omap3_pm_finish(void)
enable_hlt();
}

/* Hooks to enable / disable UART interrupts during suspend */
static int omap3_pm_begin(suspend_state_t state)
{
suspend_state = state;
omap_uart_enable_irqs(0);
return 0;
}

static void omap3_pm_end(void)
{
suspend_state = PM_SUSPEND_ON;
omap_uart_enable_irqs(1);
return;
}

static struct platform_suspend_ops omap_pm_ops = {
.begin = omap3_pm_begin,
.end = omap3_pm_end,
.prepare = omap3_pm_prepare,
.enter = omap3_pm_enter,
.finish = omap3_pm_finish,
Expand Down
14 changes: 14 additions & 0 deletions arch/arm/mach-omap2/serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,20 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
WARN_ON(ret);
}

void omap_uart_enable_irqs(int enable)
{
int ret;
struct omap_uart_state *uart;

list_for_each_entry(uart, &uart_list, node) {
if (enable)
ret = request_irq(uart->p->irq, omap_uart_interrupt,
IRQF_SHARED, "serial idle", (void *)uart);
else
free_irq(uart->p->irq, (void *)uart);
}
}

static ssize_t sleep_timeout_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
Expand Down
1 change: 1 addition & 0 deletions arch/arm/plat-omap/include/mach/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ extern void omap_uart_check_wakeup(void);
extern void omap_uart_prepare_suspend(void);
extern void omap_uart_prepare_idle(int num);
extern void omap_uart_resume_idle(int num);
extern void omap_uart_enable_irqs(int enable);
#endif

#endif

0 comments on commit 2466211

Please sign in to comment.