Commit 8c91723a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull tty and serial driver fixes from Greg KH:
 "Here are some TTY and Serial driver fixes for 5.19-rc7. They resolve a
  number of reported problems including:

   - longtime bug in pty_write() that has been reported in the past.

   - 8250 driver fixes

   - new serial device ids

   - vt overlapping data copy bugfix

   - other tiny serial driver bugfixes

  All of these have been in linux-next for a while with no reported
  problems"

* tag 'tty-5.19-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  tty: use new tty_insert_flip_string_and_push_buffer() in pty_write()
  tty: extract tty_flip_buffer_commit() from tty_flip_buffer_push()
  serial: 8250: dw: Fix the macro RZN1_UART_xDMACR_8_WORD_BURST
  vt: fix memory overlapping when deleting chars in the buffer
  serial: mvebu-uart: correctly report configured baudrate value
  serial: 8250: Fix PM usage_count for console handover
  serial: 8250: fix return error code in serial8250_request_std_resource()
  serial: stm32: Clear prev values before setting RTS delays
  tty: Add N_CAN327 line discipline ID for ELM327 based CAN driver
  serial: 8250: Fix __stop_tx() & DMA Tx restart races
  serial: pl011: UPSTAT_AUTORTS requires .throttle/unthrottle
  tty: serial: samsung_tty: set dma burst_size to 1
  serial: 8250: dw: enable using pdata with ACPI
parents c658cabb a501ab75
...@@ -111,21 +111,11 @@ static void pty_unthrottle(struct tty_struct *tty) ...@@ -111,21 +111,11 @@ static void pty_unthrottle(struct tty_struct *tty)
static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
{ {
struct tty_struct *to = tty->link; struct tty_struct *to = tty->link;
unsigned long flags;
if (tty->flow.stopped) if (tty->flow.stopped || !c)
return 0; return 0;
if (c > 0) { return tty_insert_flip_string_and_push_buffer(to->port, buf, c);
spin_lock_irqsave(&to->port->lock, flags);
/* Stuff the data into the input queue of the other end */
c = tty_insert_flip_string(to->port, buf, c);
spin_unlock_irqrestore(&to->port->lock, flags);
/* And shovel */
if (c)
tty_flip_buffer_push(to->port);
}
return c;
} }
/** /**
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/sysrq.h> #include <linux/sysrq.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
...@@ -559,6 +560,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) ...@@ -559,6 +560,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
up->port.dev = dev; up->port.dev = dev;
if (uart_console_enabled(&up->port))
pm_runtime_get_sync(up->port.dev);
serial8250_apply_quirks(up); serial8250_apply_quirks(up);
uart_add_one_port(drv, &up->port); uart_add_one_port(drv, &up->port);
} }
......
...@@ -106,10 +106,10 @@ int serial8250_tx_dma(struct uart_8250_port *p) ...@@ -106,10 +106,10 @@ int serial8250_tx_dma(struct uart_8250_port *p)
UART_XMIT_SIZE, DMA_TO_DEVICE); UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_async_issue_pending(dma->txchan); dma_async_issue_pending(dma->txchan);
if (dma->tx_err) {
dma->tx_err = 0;
serial8250_clear_THRI(p); serial8250_clear_THRI(p);
} if (dma->tx_err)
dma->tx_err = 0;
return 0; return 0;
err: err:
dma->tx_err = 1; dma->tx_err = 1;
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
#define RZN1_UART_xDMACR_DMA_EN BIT(0) #define RZN1_UART_xDMACR_DMA_EN BIT(0)
#define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1) #define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1)
#define RZN1_UART_xDMACR_4_WORD_BURST (1 << 1) #define RZN1_UART_xDMACR_4_WORD_BURST (1 << 1)
#define RZN1_UART_xDMACR_8_WORD_BURST (3 << 1) #define RZN1_UART_xDMACR_8_WORD_BURST (2 << 1)
#define RZN1_UART_xDMACR_BLK_SZ(x) ((x) << 3) #define RZN1_UART_xDMACR_BLK_SZ(x) ((x) << 3)
/* Quirks */ /* Quirks */
...@@ -773,18 +773,18 @@ static const struct of_device_id dw8250_of_match[] = { ...@@ -773,18 +773,18 @@ static const struct of_device_id dw8250_of_match[] = {
MODULE_DEVICE_TABLE(of, dw8250_of_match); MODULE_DEVICE_TABLE(of, dw8250_of_match);
static const struct acpi_device_id dw8250_acpi_match[] = { static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT33C4", 0 }, { "80860F0A", (kernel_ulong_t)&dw8250_dw_apb },
{ "INT33C5", 0 }, { "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
{ "INT3434", 0 }, { "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
{ "INT3435", 0 }, { "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb },
{ "80860F0A", 0 }, { "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb },
{ "8086228A", 0 }, { "APMC0D08", (kernel_ulong_t)&dw8250_dw_apb},
{ "APMC0D08", 0}, { "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMD0020", 0 }, { "HISI0031", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0020", 0 }, { "INT33C4", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0022", 0 }, { "INT33C5", (kernel_ulong_t)&dw8250_dw_apb },
{ "BRCM2032", 0 }, { "INT3434", (kernel_ulong_t)&dw8250_dw_apb },
{ "HISI0031", 0 }, { "INT3435", (kernel_ulong_t)&dw8250_dw_apb },
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
......
...@@ -1949,7 +1949,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) ...@@ -1949,7 +1949,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
if ((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) { if ((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) {
if (!up->dma || up->dma->tx_err) if (!up->dma || up->dma->tx_err)
serial8250_tx_chars(up); serial8250_tx_chars(up);
else else if (!up->dma->tx_running)
__stop_tx(up); __stop_tx(up);
} }
...@@ -2975,8 +2975,10 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) ...@@ -2975,8 +2975,10 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_MEM32BE: case UPIO_MEM32BE:
case UPIO_MEM16: case UPIO_MEM16:
case UPIO_MEM: case UPIO_MEM:
if (!port->mapbase) if (!port->mapbase) {
ret = -EINVAL;
break; break;
}
if (!request_mem_region(port->mapbase, size, "serial")) { if (!request_mem_region(port->mapbase, size, "serial")) {
ret = -EBUSY; ret = -EBUSY;
......
...@@ -1367,6 +1367,15 @@ static void pl011_stop_rx(struct uart_port *port) ...@@ -1367,6 +1367,15 @@ static void pl011_stop_rx(struct uart_port *port)
pl011_dma_rx_stop(uap); pl011_dma_rx_stop(uap);
} }
static void pl011_throttle_rx(struct uart_port *port)
{
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
pl011_stop_rx(port);
spin_unlock_irqrestore(&port->lock, flags);
}
static void pl011_enable_ms(struct uart_port *port) static void pl011_enable_ms(struct uart_port *port)
{ {
struct uart_amba_port *uap = struct uart_amba_port *uap =
...@@ -1788,9 +1797,10 @@ static int pl011_allocate_irq(struct uart_amba_port *uap) ...@@ -1788,9 +1797,10 @@ static int pl011_allocate_irq(struct uart_amba_port *uap)
*/ */
static void pl011_enable_interrupts(struct uart_amba_port *uap) static void pl011_enable_interrupts(struct uart_amba_port *uap)
{ {
unsigned long flags;
unsigned int i; unsigned int i;
spin_lock_irq(&uap->port.lock); spin_lock_irqsave(&uap->port.lock, flags);
/* Clear out any spuriously appearing RX interrupts */ /* Clear out any spuriously appearing RX interrupts */
pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
...@@ -1812,7 +1822,14 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap) ...@@ -1812,7 +1822,14 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
if (!pl011_dma_rx_running(uap)) if (!pl011_dma_rx_running(uap))
uap->im |= UART011_RXIM; uap->im |= UART011_RXIM;
pl011_write(uap->im, uap, REG_IMSC); pl011_write(uap->im, uap, REG_IMSC);
spin_unlock_irq(&uap->port.lock); spin_unlock_irqrestore(&uap->port.lock, flags);
}
static void pl011_unthrottle_rx(struct uart_port *port)
{
struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
pl011_enable_interrupts(uap);
} }
static int pl011_startup(struct uart_port *port) static int pl011_startup(struct uart_port *port)
...@@ -2225,6 +2242,8 @@ static const struct uart_ops amba_pl011_pops = { ...@@ -2225,6 +2242,8 @@ static const struct uart_ops amba_pl011_pops = {
.stop_tx = pl011_stop_tx, .stop_tx = pl011_stop_tx,
.start_tx = pl011_start_tx, .start_tx = pl011_start_tx,
.stop_rx = pl011_stop_rx, .stop_rx = pl011_stop_rx,
.throttle = pl011_throttle_rx,
.unthrottle = pl011_unthrottle_rx,
.enable_ms = pl011_enable_ms, .enable_ms = pl011_enable_ms,
.break_ctl = pl011_break_ctl, .break_ctl = pl011_break_ctl,
.startup = pl011_startup, .startup = pl011_startup,
......
...@@ -470,14 +470,14 @@ static void mvebu_uart_shutdown(struct uart_port *port) ...@@ -470,14 +470,14 @@ static void mvebu_uart_shutdown(struct uart_port *port)
} }
} }
static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) static unsigned int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
{ {
unsigned int d_divisor, m_divisor; unsigned int d_divisor, m_divisor;
unsigned long flags; unsigned long flags;
u32 brdv, osamp; u32 brdv, osamp;
if (!port->uartclk) if (!port->uartclk)
return -EOPNOTSUPP; return 0;
/* /*
* The baudrate is derived from the UART clock thanks to divisors: * The baudrate is derived from the UART clock thanks to divisors:
...@@ -548,7 +548,7 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) ...@@ -548,7 +548,7 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
(m_divisor << 16) | (m_divisor << 24); (m_divisor << 16) | (m_divisor << 24);
writel(osamp, port->membase + UART_OSAMP); writel(osamp, port->membase + UART_OSAMP);
return 0; return DIV_ROUND_CLOSEST(port->uartclk, d_divisor * m_divisor);
} }
static void mvebu_uart_set_termios(struct uart_port *port, static void mvebu_uart_set_termios(struct uart_port *port,
...@@ -587,15 +587,11 @@ static void mvebu_uart_set_termios(struct uart_port *port, ...@@ -587,15 +587,11 @@ static void mvebu_uart_set_termios(struct uart_port *port,
max_baud = port->uartclk / 80; max_baud = port->uartclk / 80;
baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud); baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud);
if (mvebu_uart_baud_rate_set(port, baud)) { baud = mvebu_uart_baud_rate_set(port, baud);
/* No clock available, baudrate cannot be changed */
if (old) /* In case baudrate cannot be changed, report previous old value */
baud = uart_get_baud_rate(port, old, NULL, if (baud == 0 && old)
min_baud, max_baud); baud = tty_termios_baud_rate(old);
} else {
tty_termios_encode_baud_rate(termios, baud, baud);
uart_update_timeout(port, termios->c_cflag, baud);
}
/* Only the following flag changes are supported */ /* Only the following flag changes are supported */
if (old) { if (old) {
...@@ -606,6 +602,11 @@ static void mvebu_uart_set_termios(struct uart_port *port, ...@@ -606,6 +602,11 @@ static void mvebu_uart_set_termios(struct uart_port *port,
termios->c_cflag |= CS8; termios->c_cflag |= CS8;
} }
if (baud != 0) {
tty_termios_encode_baud_rate(termios, baud, baud);
uart_update_timeout(port, termios->c_cflag, baud);
}
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
} }
......
...@@ -377,8 +377,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport) ...@@ -377,8 +377,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
/* Enable tx dma mode */ /* Enable tx dma mode */
ucon = rd_regl(port, S3C2410_UCON); ucon = rd_regl(port, S3C2410_UCON);
ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK); ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK);
ucon |= (dma_get_cache_alignment() >= 16) ? ucon |= S3C64XX_UCON_TXBURST_1;
S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1;
ucon |= S3C64XX_UCON_TXMODE_DMA; ucon |= S3C64XX_UCON_TXMODE_DMA;
wr_regl(port, S3C2410_UCON, ucon); wr_regl(port, S3C2410_UCON, ucon);
...@@ -674,7 +673,7 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport) ...@@ -674,7 +673,7 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
S3C64XX_UCON_DMASUS_EN | S3C64XX_UCON_DMASUS_EN |
S3C64XX_UCON_TIMEOUT_EN | S3C64XX_UCON_TIMEOUT_EN |
S3C64XX_UCON_RXMODE_MASK); S3C64XX_UCON_RXMODE_MASK);
ucon |= S3C64XX_UCON_RXBURST_16 | ucon |= S3C64XX_UCON_RXBURST_1 |
0xf << S3C64XX_UCON_TIMEOUT_SHIFT | 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
S3C64XX_UCON_EMPTYINT_EN | S3C64XX_UCON_EMPTYINT_EN |
S3C64XX_UCON_TIMEOUT_EN | S3C64XX_UCON_TIMEOUT_EN |
......
...@@ -1941,11 +1941,6 @@ static int uart_proc_show(struct seq_file *m, void *v) ...@@ -1941,11 +1941,6 @@ static int uart_proc_show(struct seq_file *m, void *v)
} }
#endif #endif
static inline bool uart_console_enabled(struct uart_port *port)
{
return uart_console(port) && (port->cons->flags & CON_ENABLED);
}
static void uart_port_spin_lock_init(struct uart_port *port) static void uart_port_spin_lock_init(struct uart_port *port)
{ {
spin_lock_init(&port->lock); spin_lock_init(&port->lock);
......
...@@ -72,6 +72,8 @@ static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, ...@@ -72,6 +72,8 @@ static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
*cr3 |= USART_CR3_DEM; *cr3 |= USART_CR3_DEM;
over8 = *cr1 & USART_CR1_OVER8; over8 = *cr1 & USART_CR1_OVER8;
*cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
if (over8) if (over8)
rs485_deat_dedt = delay_ADE * baud * 8; rs485_deat_dedt = delay_ADE * baud * 8;
else else
......
...@@ -111,4 +111,7 @@ static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch) ...@@ -111,4 +111,7 @@ static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch)
ssize_t redirected_tty_write(struct kiocb *, struct iov_iter *); ssize_t redirected_tty_write(struct kiocb *, struct iov_iter *);
int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
const unsigned char *chars, size_t cnt);
#endif #endif
...@@ -532,6 +532,15 @@ static void flush_to_ldisc(struct work_struct *work) ...@@ -532,6 +532,15 @@ static void flush_to_ldisc(struct work_struct *work)
} }
static inline void tty_flip_buffer_commit(struct tty_buffer *tail)
{
/*
* Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees
* buffer data.
*/
smp_store_release(&tail->commit, tail->used);
}
/** /**
* tty_flip_buffer_push - push terminal buffers * tty_flip_buffer_push - push terminal buffers
* @port: tty port to push * @port: tty port to push
...@@ -546,15 +555,42 @@ void tty_flip_buffer_push(struct tty_port *port) ...@@ -546,15 +555,42 @@ void tty_flip_buffer_push(struct tty_port *port)
{ {
struct tty_bufhead *buf = &port->buf; struct tty_bufhead *buf = &port->buf;
/* tty_flip_buffer_commit(buf->tail);
* Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees
* buffer data.
*/
smp_store_release(&buf->tail->commit, buf->tail->used);
queue_work(system_unbound_wq, &buf->work); queue_work(system_unbound_wq, &buf->work);
} }
EXPORT_SYMBOL(tty_flip_buffer_push); EXPORT_SYMBOL(tty_flip_buffer_push);
/**
* tty_insert_flip_string_and_push_buffer - add characters to the tty buffer and
* push
* @port: tty port
* @chars: characters
* @size: size
*
* The function combines tty_insert_flip_string() and tty_flip_buffer_push()
* with the exception of properly holding the @port->lock.
*
* To be used only internally (by pty currently).
*
* Returns: the number added.
*/
int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
const unsigned char *chars, size_t size)
{
struct tty_bufhead *buf = &port->buf;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
size = tty_insert_flip_string(port, chars, size);
if (size)
tty_flip_buffer_commit(buf->tail);
spin_unlock_irqrestore(&port->lock, flags);
queue_work(system_unbound_wq, &buf->work);
return size;
}
/** /**
* tty_buffer_init - prepare a tty buffer structure * tty_buffer_init - prepare a tty buffer structure
* @port: tty port to initialise * @port: tty port to initialise
......
...@@ -855,7 +855,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr) ...@@ -855,7 +855,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr)
unsigned short *p = (unsigned short *) vc->vc_pos; unsigned short *p = (unsigned short *) vc->vc_pos;
vc_uniscr_delete(vc, nr); vc_uniscr_delete(vc, nr);
scr_memcpyw(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2); scr_memmovew(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2);
scr_memsetw(p + vc->vc_cols - vc->state.x - nr, vc->vc_video_erase_char, scr_memsetw(p + vc->vc_cols - vc->state.x - nr, vc->vc_video_erase_char,
nr * 2); nr * 2);
vc->vc_need_wrap = 0; vc->vc_need_wrap = 0;
......
...@@ -390,6 +390,11 @@ static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED; ...@@ -390,6 +390,11 @@ static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
static inline int setup_earlycon(char *buf) { return 0; } static inline int setup_earlycon(char *buf) { return 0; }
#endif #endif
static inline bool uart_console_enabled(struct uart_port *port)
{
return uart_console(port) && (port->cons->flags & CON_ENABLED);
}
struct uart_port *uart_get_console(struct uart_port *ports, int nr, struct uart_port *uart_get_console(struct uart_port *ports, int nr,
struct console *c); struct console *c);
int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr, int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
......
...@@ -38,8 +38,9 @@ ...@@ -38,8 +38,9 @@
#define N_NULL 27 /* Null ldisc used for error handling */ #define N_NULL 27 /* Null ldisc used for error handling */
#define N_MCTP 28 /* MCTP-over-serial */ #define N_MCTP 28 /* MCTP-over-serial */
#define N_DEVELOPMENT 29 /* Manual out-of-tree testing */ #define N_DEVELOPMENT 29 /* Manual out-of-tree testing */
#define N_CAN327 30 /* ELM327 based OBD-II interfaces */
/* Always the newest line discipline + 1 */ /* Always the newest line discipline + 1 */
#define NR_LDISCS 30 #define NR_LDISCS 31
#endif /* _UAPI_LINUX_TTY_H */ #endif /* _UAPI_LINUX_TTY_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment