tty: serial: uartlite: Prevent changing fixed parameters

JIRA: https://issues.redhat.com/browse/RHEL-24205

commit ea017f5853e9a6a11cfa9bdc61ba823a1ed54ee8
Author: Sean Anderson <sean.anderson@seco.com>
Date:   Thu Aug 26 15:21:54 2021 -0400

    tty: serial: uartlite: Prevent changing fixed parameters

    This device does not support changing baud, parity, data bits, stop
    bits, or detecting breaks. Disable "changing" these settings to prevent
    their termios from diverging from the actual state of the uart.

    In order to determine the correct parameters to enforce, we read the
    various new devicetree parameters to discover how the uart was
    configured when it was synthesized. The defaults match
    ulite_console_setup. xlnx,use-parity, xlnx,odd-parity, and
    xlnx,data-bits are optional since there were in-tree users (and
    presumably out-of-tree users) who did not set them.

    Signed-off-by: Sean Anderson <sean.anderson@seco.com>
    Link: https://lore.kernel.org/r/20210826192154.3202269-5-sean.anderson@seco.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Signed-off-by: Andrew Halaney <ahalaney@redhat.com>
This commit is contained in:
Andrew Halaney 2024-02-21 10:57:28 -06:00 committed by Derek Barbosa
parent a9e85b9598
commit 39e6349dc1
1 changed files with 80 additions and 11 deletions

View File

@ -8,6 +8,7 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/bitfield.h>
#include <linux/console.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
@ -63,9 +64,18 @@
static struct uart_port *console_port;
#endif
/**
* struct uartlite_data: Driver private data
* reg_ops: Functions to read/write registers
* clk: Our parent clock, if present
* baud: The baud rate configured when this device was synthesized
* cflags: The cflags for parity and data bits
*/
struct uartlite_data {
const struct uartlite_reg_ops *reg_ops;
struct clk *clk;
unsigned int baud;
tcflag_t cflags;
};
struct uartlite_reg_ops {
@ -119,6 +129,8 @@ static inline void uart_out32(u32 val, u32 offset, struct uart_port *port)
static struct uart_port ulite_ports[ULITE_NR_UARTS];
static struct uart_driver ulite_uart_driver;
/* ---------------------------------------------------------------------
* Core UART driver operations
*/
@ -306,7 +318,12 @@ static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
unsigned long flags;
unsigned int baud;
struct uartlite_data *pdata = port->private_data;
/* Set termios to what the hardware supports */
termios->c_cflag &= ~(BRKINT | CSTOPB | PARENB | PARODD | CSIZE);
termios->c_cflag |= pdata->cflags & (PARENB | PARODD | CSIZE);
tty_termios_encode_baud_rate(termios, pdata->baud, pdata->baud);
spin_lock_irqsave(&port->lock, flags);
@ -329,8 +346,7 @@ static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
/* update timeout */
baud = uart_get_baud_rate(port, termios, old, 0, 460800);
uart_update_timeout(port, termios->c_cflag, baud);
uart_update_timeout(port, termios->c_cflag, pdata->baud);
spin_unlock_irqrestore(&port->lock, flags);
}
@ -532,8 +548,6 @@ static int ulite_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct uart_driver ulite_uart_driver;
static struct console ulite_console = {
.name = ULITE_NAME,
.write = ulite_console_write,
@ -765,18 +779,73 @@ static int ulite_probe(struct platform_device *pdev)
struct uartlite_data *pdata;
int irq, ret;
int id = pdev->id;
#ifdef CONFIG_OF
const __be32 *prop;
prop = of_get_property(pdev->dev.of_node, "port-number", NULL);
if (prop)
id = be32_to_cpup(prop);
#endif
pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data),
GFP_KERNEL);
if (!pdata)
return -ENOMEM;
if (IS_ENABLED(CONFIG_OF)) {
const char *prop;
struct device_node *np = pdev->dev.of_node;
u32 val = 0;
prop = "port-number";
ret = of_property_read_u32(np, prop, &id);
if (ret && ret != -EINVAL)
of_err:
return dev_err_probe(&pdev->dev, ret,
"could not read %s\n", prop);
prop = "current-speed";
ret = of_property_read_u32(np, prop, &pdata->baud);
if (ret)
goto of_err;
prop = "xlnx,use-parity";
ret = of_property_read_u32(np, prop, &val);
if (ret && ret != -EINVAL)
goto of_err;
if (val) {
prop = "xlnx,odd-parity";
ret = of_property_read_u32(np, prop, &val);
if (ret)
goto of_err;
if (val)
pdata->cflags |= PARODD;
pdata->cflags |= PARENB;
}
val = 8;
prop = "xlnx,data-bits";
ret = of_property_read_u32(np, prop, &val);
if (ret && ret != -EINVAL)
goto of_err;
switch (val) {
case 5:
pdata->cflags |= CS5;
break;
case 6:
pdata->cflags |= CS6;
break;
case 7:
pdata->cflags |= CS7;
break;
case 8:
pdata->cflags |= CS8;
break;
default:
return dev_err_probe(&pdev->dev, -EINVAL,
"bad data bits %d\n", val);
}
} else {
pdata->baud = 9600;
pdata->cflags = CS8;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;