serial: samsung: Restore IRQ mask during noirq resume
authorMichael Spang <spang@chromium.org>
Wed, 27 Mar 2013 23:34:24 +0000 (19:34 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 28 Mar 2013 23:04:19 +0000 (16:04 -0700)
This closes a window where the system may hang in resume as soon as the
UART interrupt is enabled and before the mask is restored. The hang occurs
because the driver can't handle IRQs it thinks are masked.

Signed-off-by: Michael Spang <spang@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/samsung.c

index b386fc8a5eecd7ded3303f8745c7618ccf49ced9..78d9c55a9f841710ff4652c197516954b74d7404 100644 (file)
@@ -1311,9 +1311,29 @@ static int s3c24xx_serial_resume(struct device *dev)
        return 0;
 }
 
+static int s3c24xx_serial_resume_noirq(struct device *dev)
+{
+       struct uart_port *port = s3c24xx_dev_to_port(dev);
+
+       if (port) {
+               /* restore IRQ mask */
+               if (s3c24xx_serial_has_interrupt_mask(port)) {
+                       unsigned int uintm = 0xf;
+                       if (tx_enabled(port))
+                               uintm &= ~S3C64XX_UINTM_TXD_MSK;
+                       if (rx_enabled(port))
+                               uintm &= ~S3C64XX_UINTM_RXD_MSK;
+                       wr_regl(port, S3C64XX_UINTM, uintm);
+               }
+       }
+
+       return 0;
+}
+
 static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
        .suspend = s3c24xx_serial_suspend,
        .resume = s3c24xx_serial_resume,
+       .resume_noirq = s3c24xx_serial_resume_noirq,
 };
 #define SERIAL_SAMSUNG_PM_OPS  (&s3c24xx_serial_pm_ops)