Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2466211e authored by Tero Kristo's avatar Tero Kristo Committed by Kevin Hilman
Browse files

OMAP3: Fixed crash bug with serial + suspend



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: default avatarTero Kristo <tero.kristo@nokia.com>
Signed-off-by: default avatarKevin Hilman <khilman@deeprootsystems.com>
parent 4789998a
Loading
Loading
Loading
Loading
+21 −2
Original line number Diff line number Diff line
@@ -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();
@@ -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();
@@ -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,
+14 −0
Original line number Diff line number Diff line
@@ -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)
+1 −0
Original line number Diff line number Diff line
@@ -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