[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20130910190901.GA10105@radagast>
Date: Tue, 10 Sep 2013 14:09:01 -0500
From: Felipe Balbi <balbi@...com>
To: Alexey Pelykh <alexey.pelykh@...il.com>
CC: Tony Lindgren <tony@...mide.com>,
Greg KH <gregkh@...uxfoundation.org>,
Linux OMAP Mailing List <linux-omap@...r.kernel.org>,
<linux-serial@...r.kernel.org>,
Linux Kernel Mailing List <linux-kernel@...r.kernel.org>
Subject: commit 5fe212364 causes division by zero with large bauds
Hi Alexey,
your commit 5fe212364 causes division by zero with any baud rate larger
than 3 Mbaud (IP supports up to 3686400).
Maybe this patch is all we need to get it fixed ? (untested)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 816d1a2..b50327f 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -240,8 +240,14 @@ serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud)
{
unsigned int n13 = port->uartclk / (13 * baud);
unsigned int n16 = port->uartclk / (16 * baud);
- int baudAbsDiff13 = baud - (port->uartclk / (13 * n13));
- int baudAbsDiff16 = baud - (port->uartclk / (16 * n16));
+ int baudAbsDiff13 = 0;
+ int baudAbsDiff16 = 0;
+
+ if (n13)
+ baudAbsDiff13 = baud - (port->uartclk / (13 * n13));
+ if (n16)
+ baudAbsDiff16 = baud - (port->uartclk / (16 * n16));
+
if(baudAbsDiff13 < 0)
baudAbsDiff13 = -baudAbsDiff13;
if(baudAbsDiff16 < 0)
Another possibility would be to convert this into a lookup table (also
untested):
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 816d1a2..942d68e 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -224,6 +224,48 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
pdata->enable_wakeup(up->dev, enable);
}
+struct uart_omap_config {
+ unsigned int baud;
+ unsigned int oversampling;
+ unsigned int divisor;
+};
+
+static struct uart_omap_config omap_port_configs[] = {
+ { .baud = 300, .oversampling = 16, .divisor = 10000, },
+ { .baud = 300, .oversampling = 16, .divisor = 10000, },
+ { .baud = 600, .oversampling = 16, .divisor = 5000, },
+ { .baud = 1200, .oversampling = 16, .divisor = 2500, },
+ { .baud = 2400, .oversampling = 16, .divisor = 1250, },
+ { .baud = 4800, .oversampling = 16, .divisor = 625, },
+ { .baud = 9600, .oversampling = 16, .divisor = 312, },
+ { .baud = 14400, .oversampling = 16, .divisor = 208, },
+ { .baud = 19200, .oversampling = 16, .divisor = 156, },
+ { .baud = 28800, .oversampling = 16, .divisor = 704, },
+ { .baud = 38400, .oversampling = 16, .divisor = 78, },
+ { .baud = 57600, .oversampling = 16, .divisor = 52, },
+ { .baud = 115200, .oversampling = 16, .divisor = 26, },
+ { .baud = 230400, .oversampling = 16, .divisor = 13, },
+ { .baud = 460800, .oversampling = 13, .divisor = 8, },
+ { .baud = 921600, .oversampling = 13, .divisor = 4, },
+ { .baud = 1843200, .oversampling = 13, .divisor = 2, },
+ { .baud = 3000000, .oversampling = 16, .divisor = 1, },
+ { .baud = 3686400, .oversampling = 13, .divisor = 1, },
+ { } /* Terminating Entry */
+};
+
+static struct uart_omap_config *
+__serial_omap_get_config(struct uart_port *port, unsigned int baud)
+{
+ struct uart_omap_config *cfg = omap_port_configs;
+
+ while (cfg++) {
+ if (cfg->baud == baud)
+ return cfg;
+ }
+
+ return NULL;
+}
+
/*
* serial_omap_baud_is_mode16 - check if baud rate is MODE16X
* @port: uart port info
@@ -238,16 +280,12 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
static bool
serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud)
{
- unsigned int n13 = port->uartclk / (13 * baud);
- unsigned int n16 = port->uartclk / (16 * baud);
- int baudAbsDiff13 = baud - (port->uartclk / (13 * n13));
- int baudAbsDiff16 = baud - (port->uartclk / (16 * n16));
- if(baudAbsDiff13 < 0)
- baudAbsDiff13 = -baudAbsDiff13;
- if(baudAbsDiff16 < 0)
- baudAbsDiff16 = -baudAbsDiff16;
-
- return (baudAbsDiff13 > baudAbsDiff16);
+ struct uart_omap_config *cfg = __serial_omap_get_config(port, baud);
+
+ if (!cfg)
+ return -EINVAL;
+
+ return (cfg->oversampling == 16);
}
/*
@@ -258,13 +296,12 @@ serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud)
static unsigned int
serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
{
- unsigned int divisor;
+ struct uart_omap_config *cfg = __serial_omap_get_config(port, baud);
- if (!serial_omap_baud_is_mode16(port, baud))
- divisor = 13;
- else
- divisor = 16;
- return port->uartclk/(baud * divisor);
+ if (!cfg)
+ return -EINVAL;
+
+ return cfg->divisor;
}
static void serial_omap_enable_ms(struct uart_port *port)
--
balbi
Download attachment "signature.asc" of type "application/pgp-signature" (837 bytes)
Powered by blists - more mailing lists