TTY/Serial fixes for 4.17-rc3
Here are some tty and serial driver fixes for reported issues for 4.17-rc3. Nothing major, but a number of small things: - device tree fixes/updates for serial ports - earlycon fixes - n_gsm fixes - tty core change reverted to help resolve syszkaller reports - other serial driver small fixes All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWuM0Vg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yksXgCgqT2E9Ah5O/uZp3yGAjRILKjX294AoI46+t3W Xy8WA1Fw1NCMBvfvCVIv =gBd0 -----END PGP SIGNATURE----- Merge tag 'tty-4.17-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial fixes from Greg KH: "Here are some tty and serial driver fixes for reported issues for 4.17-rc3. Nothing major, but a number of small things: - device tree fixes/updates for serial ports - earlycon fixes - n_gsm fixes - tty core change reverted to help resolve syszkaller reports - other serial driver small fixes All of these have been in linux-next with no reported issues" * tag 'tty-4.17-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: tty: Use __GFP_NOFAIL for tty_ldisc_get() tty: serial: xuartps: Setup early console when uartclk is also passed tty: Don't call panic() at tty_ldisc_init() tty: Avoid possible error pointer dereference at tty_ldisc_restore(). dt-bindings: mvebu-uart: DT fix s/interrupts-names/interrupt-names/ tty: serial: qcom_geni_serial: Use signed variable to get IRQ earlycon: Use a pointer table to fix __earlycon_table stride serial: sh-sci: Document r8a77470 bindings dt-bindings: meson-uart: DT fix s/clocks-names/clock-names/ serial: imx: fix cached UCR2 read on software reset serial: imx: warn user when using unsupported configuration serial: mvebu-uart: Fix local flags handling on termios update tty: n_gsm: Fix DLCI handling for ADM mode if debug & 2 is not set tty: n_gsm: Fix long delays with control frame timeouts in ADM mode
This commit is contained in:
commit
b52c85a7b7
|
@ -21,7 +21,7 @@ Required properties:
|
|||
- interrupts : identifier to the device interrupt
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
entry in clock names.
|
||||
- clocks-names :
|
||||
- clock-names :
|
||||
* "xtal" for external xtal clock identifier
|
||||
* "pclk" for the bus core clock, either the clk81 clock or the gate clock
|
||||
* "baud" for the source of the baudrate generator, can be either the xtal
|
||||
|
|
|
@ -24,7 +24,7 @@ Required properties:
|
|||
- Must contain two elements for the extended variant of the IP
|
||||
(marvell,armada-3700-uart-ext): "uart-tx" and "uart-rx",
|
||||
respectively the UART TX interrupt and the UART RX interrupt. A
|
||||
corresponding interrupts-names property must be defined.
|
||||
corresponding interrupt-names property must be defined.
|
||||
- For backward compatibility reasons, a single element interrupts
|
||||
property is also supported for the standard variant of the IP,
|
||||
containing only the UART sum interrupt. This form is deprecated
|
||||
|
|
|
@ -17,6 +17,8 @@ Required properties:
|
|||
- "renesas,scifa-r8a7745" for R8A7745 (RZ/G1E) SCIFA compatible UART.
|
||||
- "renesas,scifb-r8a7745" for R8A7745 (RZ/G1E) SCIFB compatible UART.
|
||||
- "renesas,hscif-r8a7745" for R8A7745 (RZ/G1E) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a77470" for R8A77470 (RZ/G1C) SCIF compatible UART.
|
||||
- "renesas,hscif-r8a77470" for R8A77470 (RZ/G1C) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a7778" for R8A7778 (R-Car M1) SCIF compatible UART.
|
||||
- "renesas,scif-r8a7779" for R8A7779 (R-Car H1) SCIF compatible UART.
|
||||
- "renesas,scif-r8a7790" for R8A7790 (R-Car H2) SCIF compatible UART.
|
||||
|
|
|
@ -942,7 +942,7 @@ int __init early_init_dt_scan_chosen_stdout(void)
|
|||
int offset;
|
||||
const char *p, *q, *options = NULL;
|
||||
int l;
|
||||
const struct earlycon_id *match;
|
||||
const struct earlycon_id **p_match;
|
||||
const void *fdt = initial_boot_params;
|
||||
|
||||
offset = fdt_path_offset(fdt, "/chosen");
|
||||
|
@ -969,7 +969,10 @@ int __init early_init_dt_scan_chosen_stdout(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
for (match = __earlycon_table; match < __earlycon_table_end; match++) {
|
||||
for (p_match = __earlycon_table; p_match < __earlycon_table_end;
|
||||
p_match++) {
|
||||
const struct earlycon_id *match = *p_match;
|
||||
|
||||
if (!match->compatible[0])
|
||||
continue;
|
||||
|
||||
|
|
|
@ -121,6 +121,9 @@ struct gsm_dlci {
|
|||
struct mutex mutex;
|
||||
|
||||
/* Link layer */
|
||||
int mode;
|
||||
#define DLCI_MODE_ABM 0 /* Normal Asynchronous Balanced Mode */
|
||||
#define DLCI_MODE_ADM 1 /* Asynchronous Disconnected Mode */
|
||||
spinlock_t lock; /* Protects the internal state */
|
||||
struct timer_list t1; /* Retransmit timer for SABM and UA */
|
||||
int retries;
|
||||
|
@ -1364,7 +1367,13 @@ retry:
|
|||
ctrl->data = data;
|
||||
ctrl->len = clen;
|
||||
gsm->pending_cmd = ctrl;
|
||||
gsm->cretries = gsm->n2;
|
||||
|
||||
/* If DLCI0 is in ADM mode skip retries, it won't respond */
|
||||
if (gsm->dlci[0]->mode == DLCI_MODE_ADM)
|
||||
gsm->cretries = 1;
|
||||
else
|
||||
gsm->cretries = gsm->n2;
|
||||
|
||||
mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
|
||||
gsm_control_transmit(gsm, ctrl);
|
||||
spin_unlock_irqrestore(&gsm->control_lock, flags);
|
||||
|
@ -1472,6 +1481,7 @@ static void gsm_dlci_t1(struct timer_list *t)
|
|||
if (debug & 8)
|
||||
pr_info("DLCI %d opening in ADM mode.\n",
|
||||
dlci->addr);
|
||||
dlci->mode = DLCI_MODE_ADM;
|
||||
gsm_dlci_open(dlci);
|
||||
} else {
|
||||
gsm_dlci_close(dlci);
|
||||
|
@ -2861,11 +2871,22 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
|
|||
static int gsm_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
|
||||
struct gsm_mux *gsm = dlci->gsm;
|
||||
|
||||
/* Not yet open so no carrier info */
|
||||
if (dlci->state != DLCI_OPEN)
|
||||
return 0;
|
||||
if (debug & 2)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Basic mode with control channel in ADM mode may not respond
|
||||
* to CMD_MSC at all and modem_rx is empty.
|
||||
*/
|
||||
if (gsm->encoding == 0 && gsm->dlci[0]->mode == DLCI_MODE_ADM &&
|
||||
!dlci->modem_rx)
|
||||
return 1;
|
||||
|
||||
return dlci->modem_rx & TIOCM_CD;
|
||||
}
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
|
|||
*/
|
||||
int __init setup_earlycon(char *buf)
|
||||
{
|
||||
const struct earlycon_id *match;
|
||||
const struct earlycon_id **p_match;
|
||||
|
||||
if (!buf || !buf[0])
|
||||
return -EINVAL;
|
||||
|
@ -177,7 +177,9 @@ int __init setup_earlycon(char *buf)
|
|||
if (early_con.flags & CON_ENABLED)
|
||||
return -EALREADY;
|
||||
|
||||
for (match = __earlycon_table; match < __earlycon_table_end; match++) {
|
||||
for (p_match = __earlycon_table; p_match < __earlycon_table_end;
|
||||
p_match++) {
|
||||
const struct earlycon_id *match = *p_match;
|
||||
size_t len = strlen(match->name);
|
||||
|
||||
if (strncmp(buf, match->name, len))
|
||||
|
|
|
@ -316,7 +316,7 @@ static u32 imx_uart_readl(struct imx_port *sport, u32 offset)
|
|||
* differ from the value that was last written. As it only
|
||||
* clears after being set, reread conditionally.
|
||||
*/
|
||||
if (sport->ucr2 & UCR2_SRST)
|
||||
if (!(sport->ucr2 & UCR2_SRST))
|
||||
sport->ucr2 = readl(sport->port.membase + offset);
|
||||
return sport->ucr2;
|
||||
break;
|
||||
|
@ -1833,6 +1833,11 @@ static int imx_uart_rs485_config(struct uart_port *port,
|
|||
rs485conf->flags &= ~SER_RS485_ENABLED;
|
||||
|
||||
if (rs485conf->flags & SER_RS485_ENABLED) {
|
||||
/* Enable receiver if low-active RTS signal is requested */
|
||||
if (sport->have_rtscts && !sport->have_rtsgpio &&
|
||||
!(rs485conf->flags & SER_RS485_RTS_ON_SEND))
|
||||
rs485conf->flags |= SER_RS485_RX_DURING_TX;
|
||||
|
||||
/* disable transmitter */
|
||||
ucr2 = imx_uart_readl(sport, UCR2);
|
||||
if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
|
||||
|
@ -2265,6 +2270,18 @@ static int imx_uart_probe(struct platform_device *pdev)
|
|||
(!sport->have_rtscts && !sport->have_rtsgpio))
|
||||
dev_err(&pdev->dev, "no RTS control, disabling rs485\n");
|
||||
|
||||
/*
|
||||
* If using the i.MX UART RTS/CTS control then the RTS (CTS_B)
|
||||
* signal cannot be set low during transmission in case the
|
||||
* receiver is off (limitation of the i.MX UART IP).
|
||||
*/
|
||||
if (sport->port.rs485.flags & SER_RS485_ENABLED &&
|
||||
sport->have_rtscts && !sport->have_rtsgpio &&
|
||||
(!(sport->port.rs485.flags & SER_RS485_RTS_ON_SEND) &&
|
||||
!(sport->port.rs485.flags & SER_RS485_RX_DURING_TX)))
|
||||
dev_err(&pdev->dev,
|
||||
"low-active RTS not possible when receiver is off, enabling receiver\n");
|
||||
|
||||
imx_uart_rs485_config(&sport->port, &sport->port.rs485);
|
||||
|
||||
/* Disable interrupts before requesting them */
|
||||
|
|
|
@ -495,7 +495,6 @@ static void mvebu_uart_set_termios(struct uart_port *port,
|
|||
termios->c_iflag |= old->c_iflag & ~(INPCK | IGNPAR);
|
||||
termios->c_cflag &= CREAD | CBAUD;
|
||||
termios->c_cflag |= old->c_cflag & ~(CREAD | CBAUD);
|
||||
termios->c_lflag = old->c_lflag;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
|
|
@ -1022,6 +1022,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
|||
struct qcom_geni_serial_port *port;
|
||||
struct uart_port *uport;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
line = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
|
@ -1061,11 +1062,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
|||
port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
|
||||
port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
|
||||
|
||||
uport->irq = platform_get_irq(pdev, 0);
|
||||
if (uport->irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get IRQ %d\n", uport->irq);
|
||||
return uport->irq;
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get IRQ %d\n", irq);
|
||||
return irq;
|
||||
}
|
||||
uport->irq = irq;
|
||||
|
||||
uport->private_data = &qcom_geni_console_driver;
|
||||
platform_set_drvdata(pdev, port);
|
||||
|
|
|
@ -1181,7 +1181,7 @@ static int __init cdns_early_console_setup(struct earlycon_device *device,
|
|||
/* only set baud if specified on command line - otherwise
|
||||
* assume it has been initialized by a boot loader.
|
||||
*/
|
||||
if (device->baud) {
|
||||
if (port->uartclk && device->baud) {
|
||||
u32 cd = 0, bdiv = 0;
|
||||
u32 mr;
|
||||
int div8;
|
||||
|
|
|
@ -2816,7 +2816,10 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
|
|||
|
||||
kref_init(&tty->kref);
|
||||
tty->magic = TTY_MAGIC;
|
||||
tty_ldisc_init(tty);
|
||||
if (tty_ldisc_init(tty)) {
|
||||
kfree(tty);
|
||||
return NULL;
|
||||
}
|
||||
tty->session = NULL;
|
||||
tty->pgrp = NULL;
|
||||
mutex_init(&tty->legacy_mutex);
|
||||
|
|
|
@ -176,12 +176,11 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
|
|||
return ERR_CAST(ldops);
|
||||
}
|
||||
|
||||
ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
|
||||
if (ld == NULL) {
|
||||
put_ldops(ldops);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/*
|
||||
* There is no way to handle allocation failure of only 16 bytes.
|
||||
* Let's simplify error handling and save more memory.
|
||||
*/
|
||||
ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL | __GFP_NOFAIL);
|
||||
ld->ops = ldops;
|
||||
ld->tty = tty;
|
||||
|
||||
|
@ -527,19 +526,16 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld)
|
|||
static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||
{
|
||||
/* There is an outstanding reference here so this is safe */
|
||||
old = tty_ldisc_get(tty, old->ops->num);
|
||||
WARN_ON(IS_ERR(old));
|
||||
tty->ldisc = old;
|
||||
tty_set_termios_ldisc(tty, old->ops->num);
|
||||
if (tty_ldisc_open(tty, old) < 0) {
|
||||
tty_ldisc_put(old);
|
||||
if (tty_ldisc_failto(tty, old->ops->num) < 0) {
|
||||
const char *name = tty_name(tty);
|
||||
|
||||
pr_warn("Falling back ldisc for %s.\n", name);
|
||||
/* The traditional behaviour is to fall back to N_TTY, we
|
||||
want to avoid falling back to N_NULL unless we have no
|
||||
choice to avoid the risk of breaking anything */
|
||||
if (tty_ldisc_failto(tty, N_TTY) < 0 &&
|
||||
tty_ldisc_failto(tty, N_NULL) < 0)
|
||||
panic("Couldn't open N_NULL ldisc for %s.",
|
||||
tty_name(tty));
|
||||
panic("Couldn't open N_NULL ldisc for %s.", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -824,12 +820,13 @@ EXPORT_SYMBOL_GPL(tty_ldisc_release);
|
|||
* the tty structure is not completely set up when this call is made.
|
||||
*/
|
||||
|
||||
void tty_ldisc_init(struct tty_struct *tty)
|
||||
int tty_ldisc_init(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
|
||||
if (IS_ERR(ld))
|
||||
panic("n_tty: init_tty");
|
||||
return PTR_ERR(ld);
|
||||
tty->ldisc = ld;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -188,7 +188,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_EARLYCON
|
||||
#define EARLYCON_TABLE() STRUCT_ALIGN(); \
|
||||
#define EARLYCON_TABLE() . = ALIGN(8); \
|
||||
VMLINUX_SYMBOL(__earlycon_table) = .; \
|
||||
KEEP(*(__earlycon_table)) \
|
||||
VMLINUX_SYMBOL(__earlycon_table_end) = .;
|
||||
|
|
|
@ -351,10 +351,10 @@ struct earlycon_id {
|
|||
char name[16];
|
||||
char compatible[128];
|
||||
int (*setup)(struct earlycon_device *, const char *options);
|
||||
} __aligned(32);
|
||||
};
|
||||
|
||||
extern const struct earlycon_id __earlycon_table[];
|
||||
extern const struct earlycon_id __earlycon_table_end[];
|
||||
extern const struct earlycon_id *__earlycon_table[];
|
||||
extern const struct earlycon_id *__earlycon_table_end[];
|
||||
|
||||
#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
|
||||
#define EARLYCON_USED_OR_UNUSED __used
|
||||
|
@ -362,12 +362,19 @@ extern const struct earlycon_id __earlycon_table_end[];
|
|||
#define EARLYCON_USED_OR_UNUSED __maybe_unused
|
||||
#endif
|
||||
|
||||
#define OF_EARLYCON_DECLARE(_name, compat, fn) \
|
||||
static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name) \
|
||||
EARLYCON_USED_OR_UNUSED __section(__earlycon_table) \
|
||||
#define _OF_EARLYCON_DECLARE(_name, compat, fn, unique_id) \
|
||||
static const struct earlycon_id unique_id \
|
||||
EARLYCON_USED_OR_UNUSED __initconst \
|
||||
= { .name = __stringify(_name), \
|
||||
.compatible = compat, \
|
||||
.setup = fn }
|
||||
.setup = fn }; \
|
||||
static const struct earlycon_id EARLYCON_USED_OR_UNUSED \
|
||||
__section(__earlycon_table) \
|
||||
* const __PASTE(__p, unique_id) = &unique_id
|
||||
|
||||
#define OF_EARLYCON_DECLARE(_name, compat, fn) \
|
||||
_OF_EARLYCON_DECLARE(_name, compat, fn, \
|
||||
__UNIQUE_ID(__earlycon_##_name))
|
||||
|
||||
#define EARLYCON_DECLARE(_name, fn) OF_EARLYCON_DECLARE(_name, "", fn)
|
||||
|
||||
|
|
|
@ -701,7 +701,7 @@ extern int tty_unregister_ldisc(int disc);
|
|||
extern int tty_set_ldisc(struct tty_struct *tty, int disc);
|
||||
extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty);
|
||||
extern void tty_ldisc_release(struct tty_struct *tty);
|
||||
extern void tty_ldisc_init(struct tty_struct *tty);
|
||||
extern int __must_check tty_ldisc_init(struct tty_struct *tty);
|
||||
extern void tty_ldisc_deinit(struct tty_struct *tty);
|
||||
extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
|
||||
char *f, int count);
|
||||
|
|
Loading…
Reference in a new issue