TTY/Serial driver fixes for 5.17-rc2

Here are some small bug fixes and reverts for reported problems with the
 tty core and drivers.  They include:
 	- revert the fifo use for the 8250 console mode.  It caused too
 	  many regressions and problems, and had a bug in it as well.
 	  This is being reworked and should show up in a later -rc1
 	  release, but it's not ready for 5.17
 	- rpmsg tty race fix
 	- restore the cyclades.h uapi header file.  Turns out a compiler
 	  test suite used it for some unknown reason.  Bring it back
 	  just for the parts that are used by the builder test so they
 	  continue to build.  No functionality is restored as no one
 	  actually has this hardware anymore, nor is it really tested.
 	- stm32 driver fixes
 	- n_gsm flow control fixes
 	- pl011 driver fix
 	- rs485 initialization fix
 
 All of these have been in linux-next this week with no reported
 problems.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYfU8Qw8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ynkJQCfb/B943LpvBd0x1gDxwCraZ0ruNQAoI1GCT5v
 fP5ATuBpZnS92MCB2961
 =WfuL
 -----END PGP SIGNATURE-----

Merge tag 'tty-5.17-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial driver fixes from Greg KH:
 "Here are some small bug fixes and reverts for reported problems with
  the tty core and drivers. They include:

   - revert the fifo use for the 8250 console mode. It caused too many
     regressions and problems, and had a bug in it as well. This is
     being reworked and should show up in a later -rc1 release, but it's
     not ready for 5.17

   - rpmsg tty race fix

   - restore the cyclades.h uapi header file. Turns out a compiler test
     suite used it for some unknown reason. Bring it back just for the
     parts that are used by the builder test so they continue to build.
     No functionality is restored as no one actually has this hardware
     anymore, nor is it really tested.

   - stm32 driver fixes

   - n_gsm flow control fixes

   - pl011 driver fix

   - rs485 initialization fix

  All of these have been in linux-next this week with no reported
  problems"

* tag 'tty-5.17-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  kbuild: remove include/linux/cyclades.h from header file check
  serial: core: Initialize rs485 RTS polarity already on probe
  serial: pl011: Fix incorrect rs485 RTS polarity on set_mctrl
  serial: stm32: fix software flow control transfer
  serial: stm32: prevent TDR register overwrite when sending x_char
  tty: n_gsm: fix SW flow control encoding/handling
  serial: 8250: of: Fix mapped region size when using reg-offset property
  tty: rpmsg: Fix race condition releasing tty port
  tty: Partially revert the removal of the Cyclades public API
  tty: Add support for Brainboxes UC cards.
  Revert "tty: serial: Use fifo in 8250 console driver"
This commit is contained in:
Linus Torvalds 2022-01-29 15:23:13 +02:00
Родитель 44aa31a2bf d1ad2721b1
Коммит bb37101b36
10 изменённых файлов: 205 добавлений и 106 удалений

Просмотреть файл

@ -322,6 +322,7 @@ static int addr_cnt;
#define GSM1_ESCAPE_BITS 0x20
#define XON 0x11
#define XOFF 0x13
#define ISO_IEC_646_MASK 0x7F
static const struct tty_port_operations gsm_port_ops;
@ -531,7 +532,8 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
int olen = 0;
while (len--) {
if (*input == GSM1_SOF || *input == GSM1_ESCAPE
|| *input == XON || *input == XOFF) {
|| (*input & ISO_IEC_646_MASK) == XON
|| (*input & ISO_IEC_646_MASK) == XOFF) {
*output++ = GSM1_ESCAPE;
*output++ = *input++ ^ GSM1_ESCAPE_BITS;
olen++;

Просмотреть файл

@ -50,10 +50,17 @@ static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len, void *p
static int rpmsg_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct rpmsg_tty_port *cport = idr_find(&tty_idr, tty->index);
struct tty_port *port;
tty->driver_data = cport;
return tty_port_install(&cport->port, driver, tty);
port = tty_port_get(&cport->port);
return tty_port_install(port, driver, tty);
}
static void rpmsg_tty_cleanup(struct tty_struct *tty)
{
tty_port_put(tty->port);
}
static int rpmsg_tty_open(struct tty_struct *tty, struct file *filp)
@ -106,12 +113,19 @@ static unsigned int rpmsg_tty_write_room(struct tty_struct *tty)
return size;
}
static void rpmsg_tty_hangup(struct tty_struct *tty)
{
tty_port_hangup(tty->port);
}
static const struct tty_operations rpmsg_tty_ops = {
.install = rpmsg_tty_install,
.open = rpmsg_tty_open,
.close = rpmsg_tty_close,
.write = rpmsg_tty_write,
.write_room = rpmsg_tty_write_room,
.hangup = rpmsg_tty_hangup,
.cleanup = rpmsg_tty_cleanup,
};
static struct rpmsg_tty_port *rpmsg_tty_alloc_cport(void)
@ -137,8 +151,10 @@ static struct rpmsg_tty_port *rpmsg_tty_alloc_cport(void)
return cport;
}
static void rpmsg_tty_release_cport(struct rpmsg_tty_port *cport)
static void rpmsg_tty_destruct_port(struct tty_port *port)
{
struct rpmsg_tty_port *cport = container_of(port, struct rpmsg_tty_port, port);
mutex_lock(&idr_lock);
idr_remove(&tty_idr, cport->id);
mutex_unlock(&idr_lock);
@ -146,7 +162,10 @@ static void rpmsg_tty_release_cport(struct rpmsg_tty_port *cport)
kfree(cport);
}
static const struct tty_port_operations rpmsg_tty_port_ops = { };
static const struct tty_port_operations rpmsg_tty_port_ops = {
.destruct = rpmsg_tty_destruct_port,
};
static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
{
@ -166,7 +185,8 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
cport->id, dev);
if (IS_ERR(tty_dev)) {
ret = dev_err_probe(dev, PTR_ERR(tty_dev), "Failed to register tty port\n");
goto err_destroy;
tty_port_put(&cport->port);
return ret;
}
cport->rpdev = rpdev;
@ -177,12 +197,6 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
rpdev->src, rpdev->dst, cport->id);
return 0;
err_destroy:
tty_port_destroy(&cport->port);
rpmsg_tty_release_cport(cport);
return ret;
}
static void rpmsg_tty_remove(struct rpmsg_device *rpdev)
@ -192,13 +206,11 @@ static void rpmsg_tty_remove(struct rpmsg_device *rpdev)
dev_dbg(&rpdev->dev, "Removing rpmsg tty device %d\n", cport->id);
/* User hang up to release the tty */
if (tty_port_initialized(&cport->port))
tty_port_tty_hangup(&cport->port, false);
tty_port_tty_hangup(&cport->port, false);
tty_unregister_device(rpmsg_tty_driver, cport->id);
tty_port_destroy(&cport->port);
rpmsg_tty_release_cport(cport);
tty_port_put(&cport->port);
}
static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = {

Просмотреть файл

@ -83,8 +83,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->mapsize = resource_size(&resource);
/* Check for shifted address mapping */
if (of_property_read_u32(np, "reg-offset", &prop) == 0)
if (of_property_read_u32(np, "reg-offset", &prop) == 0) {
if (prop >= port->mapsize) {
dev_warn(&ofdev->dev, "reg-offset %u exceeds region size %pa\n",
prop, &port->mapsize);
ret = -EINVAL;
goto err_unprepare;
}
port->mapbase += prop;
port->mapsize -= prop;
}
port->iotype = UPIO_MEM;
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {

Просмотреть файл

@ -4779,8 +4779,30 @@ static const struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0dc0 */
pbn_b2_4_115200 },
/* Brainboxes Devices */
/*
* BrainBoxes UC-260
* Brainboxes UC-101
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x0BA1,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_2_115200 },
/*
* Brainboxes UC-235/246
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x0AA1,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_1_115200 },
/*
* Brainboxes UC-257
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x0861,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_2_115200 },
/*
* Brainboxes UC-260/271/701/756
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x0D21,
PCI_ANY_ID, PCI_ANY_ID,
@ -4788,7 +4810,81 @@ static const struct pci_device_id serial_pci_tbl[] = {
pbn_b2_4_115200 },
{ PCI_VENDOR_ID_INTASHIELD, 0x0E34,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
pbn_b2_4_115200 },
/*
* Brainboxes UC-268
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x0841,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_4_115200 },
/*
* Brainboxes UC-275/279
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x0881,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_8_115200 },
/*
* Brainboxes UC-302
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x08E1,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_2_115200 },
/*
* Brainboxes UC-310
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x08C1,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_2_115200 },
/*
* Brainboxes UC-313
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x08A3,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_2_115200 },
/*
* Brainboxes UC-320/324
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x0A61,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_1_115200 },
/*
* Brainboxes UC-346
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x0B02,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_4_115200 },
/*
* Brainboxes UC-357
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x0A81,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_2_115200 },
{ PCI_VENDOR_ID_INTASHIELD, 0x0A83,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_2_115200 },
/*
* Brainboxes UC-368
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x0C41,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_4_115200 },
/*
* Brainboxes UC-420/431
*/
{ PCI_VENDOR_ID_INTASHIELD, 0x0921,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_4_115200 },
/*
* Perle PCI-RAS cards

Просмотреть файл

@ -2056,7 +2056,10 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
serial8250_rpm_put(up);
}
static void wait_for_lsr(struct uart_8250_port *up, int bits)
/*
* Wait for transmitter & holding register to empty
*/
static void wait_for_xmitr(struct uart_8250_port *up, int bits)
{
unsigned int status, tmout = 10000;
@ -2073,16 +2076,6 @@ static void wait_for_lsr(struct uart_8250_port *up, int bits)
udelay(1);
touch_nmi_watchdog();
}
}
/*
* Wait for transmitter & holding register to empty
*/
static void wait_for_xmitr(struct uart_8250_port *up, int bits)
{
unsigned int tmout;
wait_for_lsr(up, bits);
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
@ -3332,35 +3325,6 @@ static void serial8250_console_restore(struct uart_8250_port *up)
serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
}
/*
* Print a string to the serial port using the device FIFO
*
* It sends fifosize bytes and then waits for the fifo
* to get empty.
*/
static void serial8250_console_fifo_write(struct uart_8250_port *up,
const char *s, unsigned int count)
{
int i;
const char *end = s + count;
unsigned int fifosize = up->port.fifosize;
bool cr_sent = false;
while (s != end) {
wait_for_lsr(up, UART_LSR_THRE);
for (i = 0; i < fifosize && s != end; ++i) {
if (*s == '\n' && !cr_sent) {
serial_out(up, UART_TX, '\r');
cr_sent = true;
} else {
serial_out(up, UART_TX, *s++);
cr_sent = false;
}
}
}
}
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
@ -3376,7 +3340,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
struct uart_8250_em485 *em485 = up->em485;
struct uart_port *port = &up->port;
unsigned long flags;
unsigned int ier, use_fifo;
unsigned int ier;
int locked = 1;
touch_nmi_watchdog();
@ -3408,20 +3372,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
mdelay(port->rs485.delay_rts_before_send);
}
use_fifo = (up->capabilities & UART_CAP_FIFO) &&
port->fifosize > 1 &&
(serial_port_in(port, UART_FCR) & UART_FCR_ENABLE_FIFO) &&
/*
* After we put a data in the fifo, the controller will send
* it regardless of the CTS state. Therefore, only use fifo
* if we don't use control flow.
*/
!(up->port.flags & UPF_CONS_FLOW);
if (likely(use_fifo))
serial8250_console_fifo_write(up, s, count);
else
uart_console_write(port, s, count, serial8250_console_putchar);
uart_console_write(port, s, count, serial8250_console_putchar);
/*
* Finally, wait for transmitter to become empty

Просмотреть файл

@ -1582,9 +1582,6 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
container_of(port, struct uart_amba_port, port);
unsigned int cr;
if (port->rs485.flags & SER_RS485_ENABLED)
mctrl &= ~TIOCM_RTS;
cr = pl011_read(uap, REG_CR);
#define TIOCMBIT(tiocmbit, uartbit) \
@ -1808,14 +1805,8 @@ static int pl011_startup(struct uart_port *port)
cr &= UART011_CR_RTS | UART011_CR_DTR;
cr |= UART01x_CR_UARTEN | UART011_CR_RXE;
if (port->rs485.flags & SER_RS485_ENABLED) {
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
cr &= ~UART011_CR_RTS;
else
cr |= UART011_CR_RTS;
} else {
if (!(port->rs485.flags & SER_RS485_ENABLED))
cr |= UART011_CR_TXE;
}
pl011_write(cr, uap, REG_CR);

Просмотреть файл

@ -144,6 +144,11 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
unsigned long flags;
unsigned int old;
if (port->rs485.flags & SER_RS485_ENABLED) {
set &= ~TIOCM_RTS;
clear &= ~TIOCM_RTS;
}
spin_lock_irqsave(&port->lock, flags);
old = port->mctrl;
port->mctrl = (old & ~clear) | set;
@ -157,23 +162,10 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
static void uart_port_dtr_rts(struct uart_port *uport, int raise)
{
int rs485_on = uport->rs485_config &&
(uport->rs485.flags & SER_RS485_ENABLED);
int RTS_after_send = !!(uport->rs485.flags & SER_RS485_RTS_AFTER_SEND);
if (raise) {
if (rs485_on && RTS_after_send) {
uart_set_mctrl(uport, TIOCM_DTR);
uart_clear_mctrl(uport, TIOCM_RTS);
} else {
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
}
} else {
unsigned int clear = TIOCM_DTR;
clear |= (!rs485_on || RTS_after_send) ? TIOCM_RTS : 0;
uart_clear_mctrl(uport, clear);
}
if (raise)
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
else
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
}
/*
@ -1075,11 +1067,6 @@ uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
goto out;
if (!tty_io_error(tty)) {
if (uport->rs485.flags & SER_RS485_ENABLED) {
set &= ~TIOCM_RTS;
clear &= ~TIOCM_RTS;
}
uart_update_mctrl(uport, set, clear);
ret = 0;
}
@ -2390,6 +2377,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
*/
spin_lock_irqsave(&port->lock, flags);
port->mctrl &= TIOCM_DTR;
if (port->rs485.flags & SER_RS485_ENABLED &&
!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND))
port->mctrl |= TIOCM_RTS;
port->ops->set_mctrl(port, port->mctrl);
spin_unlock_irqrestore(&port->lock, flags);

Просмотреть файл

@ -550,11 +550,23 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct circ_buf *xmit = &port->state->xmit;
u32 isr;
int ret;
if (port->x_char) {
if (stm32_usart_tx_dma_started(stm32_port) &&
stm32_usart_tx_dma_enabled(stm32_port))
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
/* Check that TDR is empty before filling FIFO */
ret =
readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
isr,
(isr & USART_SR_TXE),
10, 1000);
if (ret)
dev_warn(port->dev, "1 character may be erased\n");
writel_relaxed(port->x_char, port->membase + ofs->tdr);
port->x_char = 0;
port->icount.tx++;
@ -730,7 +742,7 @@ static void stm32_usart_start_tx(struct uart_port *port)
struct serial_rs485 *rs485conf = &port->rs485;
struct circ_buf *xmit = &port->state->xmit;
if (uart_circ_empty(xmit))
if (uart_circ_empty(xmit) && !port->x_char)
return;
if (rs485conf->flags & SER_RS485_ENABLED) {

Просмотреть файл

@ -0,0 +1,35 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI_LINUX_CYCLADES_H
#define _UAPI_LINUX_CYCLADES_H
#warning "Support for features provided by this header has been removed"
#warning "Please consider updating your code"
struct cyclades_monitor {
unsigned long int_count;
unsigned long char_count;
unsigned long char_max;
unsigned long char_last;
};
#define CYGETMON 0x435901
#define CYGETTHRESH 0x435902
#define CYSETTHRESH 0x435903
#define CYGETDEFTHRESH 0x435904
#define CYSETDEFTHRESH 0x435905
#define CYGETTIMEOUT 0x435906
#define CYSETTIMEOUT 0x435907
#define CYGETDEFTIMEOUT 0x435908
#define CYSETDEFTIMEOUT 0x435909
#define CYSETRFLOW 0x43590a
#define CYGETRFLOW 0x43590b
#define CYSETRTSDTR_INV 0x43590c
#define CYGETRTSDTR_INV 0x43590d
#define CYZSETPOLLCYCLE 0x43590e
#define CYZGETPOLLCYCLE 0x43590f
#define CYGETCD1400VER 0x435910
#define CYSETWAIT 0x435912
#define CYGETWAIT 0x435913
#endif /* _UAPI_LINUX_CYCLADES_H */

Просмотреть файл

@ -28,6 +28,7 @@ no-header-test += linux/am437x-vpfe.h
no-header-test += linux/android/binder.h
no-header-test += linux/android/binderfs.h
no-header-test += linux/coda.h
no-header-test += linux/cyclades.h
no-header-test += linux/errqueue.h
no-header-test += linux/fsmap.h
no-header-test += linux/hdlc/ioctl.h