]> git.itanic.dy.fi Git - linux-stable/commitdiff
serial: max310x: prevent infinite while() loop in port startup
authorHugo Villeneuve <hvilleneuve@dimonoff.com>
Tue, 16 Jan 2024 21:30:01 +0000 (16:30 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 23 Feb 2024 08:12:42 +0000 (09:12 +0100)
commit b35f8dbbce818b02c730dc85133dc7754266e084 upstream.

If there is a problem after resetting a port, the do/while() loop that
checks the default value of DIVLSB register may run forever and spam the
I2C bus.

Add a delay before each read of DIVLSB, and a maximum number of tries to
prevent that situation from happening.

Also fail probe if port reset is unsuccessful.

Fixes: 10d8b34a4217 ("serial: max310x: Driver rework")
Cc: stable@vger.kernel.org
Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Link: https://lore.kernel.org/r/20240116213001.3691629-5-hugo@hugovil.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/max310x.c

index e91a2a59d9f00601ed9e2e06253189a33cc225a1..163a89f84c9c2b77d51698ae7487c670b14ffa39 100644 (file)
 #define MAX310x_REV_MASK               (0xf8)
 #define MAX310X_WRITE_BIT              0x80
 
+/* Port startup definitions */
+#define MAX310X_PORT_STARTUP_WAIT_RETRIES      20 /* Number of retries */
+#define MAX310X_PORT_STARTUP_WAIT_DELAY_MS     10 /* Delay between retries */
+
 /* Crystal-related definitions */
 #define MAX310X_XTAL_WAIT_RETRIES      20 /* Number of retries */
 #define MAX310X_XTAL_WAIT_DELAY_MS     10 /* Delay between retries */
@@ -1349,6 +1353,9 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
                goto out_clk;
 
        for (i = 0; i < devtype->nr; i++) {
+               bool started = false;
+               unsigned int try = 0, val = 0;
+
                /* Reset port */
                regmap_write(regmaps[i], MAX310X_MODE2_REG,
                             MAX310X_MODE2_RST_BIT);
@@ -1357,8 +1364,17 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
 
                /* Wait for port startup */
                do {
-                       regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &ret);
-               } while (ret != 0x01);
+                       msleep(MAX310X_PORT_STARTUP_WAIT_DELAY_MS);
+                       regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &val);
+
+                       if (val == 0x01)
+                               started = true;
+               } while (!started && (++try < MAX310X_PORT_STARTUP_WAIT_RETRIES));
+
+               if (!started) {
+                       ret = dev_err_probe(dev, -EAGAIN, "port reset failed\n");
+                       goto out_uart;
+               }
 
                regmap_write(regmaps[i], MAX310X_MODE1_REG, devtype->mode1);
        }