aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/sh-sci.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2013-11-28 12:11:45 -0500
committerSimon Horman <horms+renesas@verge.net.au>2013-12-13 19:58:12 -0500
commitcaec70381b469d6ed1bd3d0441a19aa6de0bbff3 (patch)
tree8a68b6cc78511ef077c56fecbc854dc991050dd2 /drivers/tty/serial/sh-sci.c
parente2afca6988c335d2ec7b66f2fadcd63286570bf8 (diff)
serial: sh-sci: Don't enable/disable port from within break timer
The break timer accesses hardware registers and thus requires the port to be enabled. It currently ensures this by enabling the port at the beginning of the timer handler, and disabling it at the end. However, the enable/disable operations call the runtime PM sync functions, which are not allowed in atomic context. The current situation is thus broken. This change relies on non-atomic code to enable/disable the port. The break timer will only be started from the IRQ handler, which already runs with the port enabled. We just need to ensure that the port won't be disabled with the timer running, and that's easily done by just cancelling the timer in the port disable function. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Acked-by: Magnus Damm <damm@opensource.se> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
-rw-r--r--drivers/tty/serial/sh-sci.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 6e5ce628b4eb..1ebac3e9e53a 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -431,6 +431,14 @@ static void sci_port_disable(struct sci_port *sci_port)
431 if (!sci_port->port.dev) 431 if (!sci_port->port.dev)
432 return; 432 return;
433 433
434 /* Cancel the break timer to ensure that the timer handler will not try
435 * to access the hardware with clocks and power disabled. Reset the
436 * break flag to make the break debouncing state machine ready for the
437 * next break.
438 */
439 del_timer_sync(&sci_port->break_timer);
440 sci_port->break_flag = 0;
441
434 clk_disable(sci_port->fclk); 442 clk_disable(sci_port->fclk);
435 clk_disable(sci_port->iclk); 443 clk_disable(sci_port->iclk);
436 444
@@ -733,8 +741,6 @@ static void sci_break_timer(unsigned long data)
733{ 741{
734 struct sci_port *port = (struct sci_port *)data; 742 struct sci_port *port = (struct sci_port *)data;
735 743
736 sci_port_enable(port);
737
738 if (sci_rxd_in(&port->port) == 0) { 744 if (sci_rxd_in(&port->port) == 0) {
739 port->break_flag = 1; 745 port->break_flag = 1;
740 sci_schedule_break_timer(port); 746 sci_schedule_break_timer(port);
@@ -744,8 +750,6 @@ static void sci_break_timer(unsigned long data)
744 sci_schedule_break_timer(port); 750 sci_schedule_break_timer(port);
745 } else 751 } else
746 port->break_flag = 0; 752 port->break_flag = 0;
747
748 sci_port_disable(port);
749} 753}
750 754
751static int sci_handle_errors(struct uart_port *port) 755static int sci_handle_errors(struct uart_port *port)