[1/3] serial: pl011: safeguard against impossible baudrates

Message ID 1348134346-25593-1-git-send-email-linus.walleij@stericsson.com
State New
Headers show

Commit Message

Linus Walleij Sept. 20, 2012, 9:45 a.m.
From: Linus Walleij <linus.walleij@linaro.org>

The PL011 generates it's bitrate from the clock to the block,
and this in turn will be divided by a minimum of 16 (ARM PL011)
or 8 (ST Micro PL011 derivate). Safeguard against illegal
rates exceeding that of what the port clock can be divided
down to.

Since the clkdiv variable is only ever used for calculating the
maximum baud rate, let's skip that variable and add a new
max_baud variable instead, then use this to check limits and
as parameter for getting the baud rate.

Cc: Par-Gunnar Hjalmdahl <par-gunnar.hjalmdahl@stericsson.com>
Cc: Guillaume Jaunet <guillaume.jaunet@stericsson.com>
Cc: Christophe Arnal <christophe.arnal@stericsson.com>
Cc: Matthias Locher <matthias.locher@stericsson.com>
Cc: Rajanikanth H.V <rajanikanth.hv@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/tty/serial/amba-pl011.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

Patch

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index d626d84..9e16ea6 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1492,18 +1492,25 @@  pl011_set_termios(struct uart_port *port, struct ktermios *termios,
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int lcr_h, old_cr;
 	unsigned long flags;
-	unsigned int baud, quot, clkdiv;
+	unsigned int max_baud, baud, quot;
 
 	if (uap->vendor->oversampling)
-		clkdiv = 8;
+		max_baud = port->uartclk / 8;
 	else
-		clkdiv = 16;
+		max_baud = port->uartclk / 16;
+
+	if ((termios->c_ispeed > max_baud) ||
+	    (termios->c_ospeed > max_baud)) {
+		dev_err(port->dev,
+			"requested a baud rate > clock/mindivisor\n");
+		return;
+	}
 
 	/*
 	 * Ask the core to calculate the divisor for us.
 	 */
 	baud = uart_get_baud_rate(port, termios, old, 0,
-				  port->uartclk / clkdiv);
+				  max_baud);
 
 	if (baud > port->uartclk/16)
 		quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);