forked from Minki/linux
TTY / Serial driver fixes for 5.19-rc7
Here are some TTY and Serial driver fixes for 5.19-rc7. They resolve a number of reported problems including: - long time 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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYtJZSg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymDUQCfbfzfsMweUSiEjcfENNV4o52o3JgAn3MudgIV y1gogwEVkYK6q5itgi3W =ZAlt -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
8c91723ac9
@ -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)
|
||||
{
|
||||
struct tty_struct *to = tty->link;
|
||||
unsigned long flags;
|
||||
|
||||
if (tty->flow.stopped)
|
||||
if (tty->flow.stopped || !c)
|
||||
return 0;
|
||||
|
||||
if (c > 0) {
|
||||
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;
|
||||
return tty_insert_flip_string_and_push_buffer(to->port, buf, c);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/tty_flip.h>
|
||||
@ -559,6 +560,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
|
||||
|
||||
up->port.dev = dev;
|
||||
|
||||
if (uart_console_enabled(&up->port))
|
||||
pm_runtime_get_sync(up->port.dev);
|
||||
|
||||
serial8250_apply_quirks(up);
|
||||
uart_add_one_port(drv, &up->port);
|
||||
}
|
||||
|
@ -106,10 +106,10 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
|
||||
dma_async_issue_pending(dma->txchan);
|
||||
if (dma->tx_err) {
|
||||
serial8250_clear_THRI(p);
|
||||
if (dma->tx_err)
|
||||
dma->tx_err = 0;
|
||||
serial8250_clear_THRI(p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dma->tx_err = 1;
|
||||
|
@ -47,7 +47,7 @@
|
||||
#define RZN1_UART_xDMACR_DMA_EN BIT(0)
|
||||
#define RZN1_UART_xDMACR_1_WORD_BURST (0 << 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)
|
||||
|
||||
/* Quirks */
|
||||
@ -773,18 +773,18 @@ static const struct of_device_id dw8250_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, dw8250_of_match);
|
||||
|
||||
static const struct acpi_device_id dw8250_acpi_match[] = {
|
||||
{ "INT33C4", 0 },
|
||||
{ "INT33C5", 0 },
|
||||
{ "INT3434", 0 },
|
||||
{ "INT3435", 0 },
|
||||
{ "80860F0A", 0 },
|
||||
{ "8086228A", 0 },
|
||||
{ "APMC0D08", 0},
|
||||
{ "AMD0020", 0 },
|
||||
{ "AMDI0020", 0 },
|
||||
{ "AMDI0022", 0 },
|
||||
{ "BRCM2032", 0 },
|
||||
{ "HISI0031", 0 },
|
||||
{ "80860F0A", (kernel_ulong_t)&dw8250_dw_apb },
|
||||
{ "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
|
||||
{ "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
|
||||
{ "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb },
|
||||
{ "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb },
|
||||
{ "APMC0D08", (kernel_ulong_t)&dw8250_dw_apb},
|
||||
{ "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb },
|
||||
{ "HISI0031", (kernel_ulong_t)&dw8250_dw_apb },
|
||||
{ "INT33C4", (kernel_ulong_t)&dw8250_dw_apb },
|
||||
{ "INT33C5", (kernel_ulong_t)&dw8250_dw_apb },
|
||||
{ "INT3434", (kernel_ulong_t)&dw8250_dw_apb },
|
||||
{ "INT3435", (kernel_ulong_t)&dw8250_dw_apb },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
|
||||
|
@ -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 (!up->dma || up->dma->tx_err)
|
||||
serial8250_tx_chars(up);
|
||||
else
|
||||
else if (!up->dma->tx_running)
|
||||
__stop_tx(up);
|
||||
}
|
||||
|
||||
@ -2975,8 +2975,10 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
|
||||
case UPIO_MEM32BE:
|
||||
case UPIO_MEM16:
|
||||
case UPIO_MEM:
|
||||
if (!port->mapbase)
|
||||
if (!port->mapbase) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!request_mem_region(port->mapbase, size, "serial")) {
|
||||
ret = -EBUSY;
|
||||
|
@ -1367,6 +1367,15 @@ static void pl011_stop_rx(struct uart_port *port)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int i;
|
||||
|
||||
spin_lock_irq(&uap->port.lock);
|
||||
spin_lock_irqsave(&uap->port.lock, flags);
|
||||
|
||||
/* Clear out any spuriously appearing RX interrupts */
|
||||
pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
|
||||
@ -1812,7 +1822,14 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
|
||||
if (!pl011_dma_rx_running(uap))
|
||||
uap->im |= UART011_RXIM;
|
||||
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)
|
||||
@ -2225,6 +2242,8 @@ static const struct uart_ops amba_pl011_pops = {
|
||||
.stop_tx = pl011_stop_tx,
|
||||
.start_tx = pl011_start_tx,
|
||||
.stop_rx = pl011_stop_rx,
|
||||
.throttle = pl011_throttle_rx,
|
||||
.unthrottle = pl011_unthrottle_rx,
|
||||
.enable_ms = pl011_enable_ms,
|
||||
.break_ctl = pl011_break_ctl,
|
||||
.startup = pl011_startup,
|
||||
|
@ -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 long flags;
|
||||
u32 brdv, osamp;
|
||||
|
||||
if (!port->uartclk)
|
||||
return -EOPNOTSUPP;
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
(m_divisor << 16) | (m_divisor << 24);
|
||||
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,
|
||||
@ -587,15 +587,11 @@ static void mvebu_uart_set_termios(struct uart_port *port,
|
||||
max_baud = port->uartclk / 80;
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud);
|
||||
if (mvebu_uart_baud_rate_set(port, baud)) {
|
||||
/* No clock available, baudrate cannot be changed */
|
||||
if (old)
|
||||
baud = uart_get_baud_rate(port, old, NULL,
|
||||
min_baud, max_baud);
|
||||
} else {
|
||||
tty_termios_encode_baud_rate(termios, baud, baud);
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
}
|
||||
baud = mvebu_uart_baud_rate_set(port, baud);
|
||||
|
||||
/* In case baudrate cannot be changed, report previous old value */
|
||||
if (baud == 0 && old)
|
||||
baud = tty_termios_baud_rate(old);
|
||||
|
||||
/* Only the following flag changes are supported */
|
||||
if (old) {
|
||||
@ -606,6 +602,11 @@ static void mvebu_uart_set_termios(struct uart_port *port,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -377,8 +377,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
|
||||
/* Enable tx dma mode */
|
||||
ucon = rd_regl(port, S3C2410_UCON);
|
||||
ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK);
|
||||
ucon |= (dma_get_cache_alignment() >= 16) ?
|
||||
S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1;
|
||||
ucon |= S3C64XX_UCON_TXBURST_1;
|
||||
ucon |= S3C64XX_UCON_TXMODE_DMA;
|
||||
wr_regl(port, S3C2410_UCON, ucon);
|
||||
|
||||
@ -674,7 +673,7 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
|
||||
S3C64XX_UCON_DMASUS_EN |
|
||||
S3C64XX_UCON_TIMEOUT_EN |
|
||||
S3C64XX_UCON_RXMODE_MASK);
|
||||
ucon |= S3C64XX_UCON_RXBURST_16 |
|
||||
ucon |= S3C64XX_UCON_RXBURST_1 |
|
||||
0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
|
||||
S3C64XX_UCON_EMPTYINT_EN |
|
||||
S3C64XX_UCON_TIMEOUT_EN |
|
||||
|
@ -1941,11 +1941,6 @@ static int uart_proc_show(struct seq_file *m, void *v)
|
||||
}
|
||||
#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)
|
||||
{
|
||||
spin_lock_init(&port->lock);
|
||||
|
@ -72,6 +72,8 @@ static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
|
||||
*cr3 |= USART_CR3_DEM;
|
||||
over8 = *cr1 & USART_CR1_OVER8;
|
||||
|
||||
*cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
|
||||
|
||||
if (over8)
|
||||
rs485_deat_dedt = delay_ADE * baud * 8;
|
||||
else
|
||||
|
@ -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 *);
|
||||
|
||||
int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
|
||||
const unsigned char *chars, size_t cnt);
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
* @port: tty port to push
|
||||
@ -546,15 +555,42 @@ void tty_flip_buffer_push(struct tty_port *port)
|
||||
{
|
||||
struct tty_bufhead *buf = &port->buf;
|
||||
|
||||
/*
|
||||
* Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees
|
||||
* buffer data.
|
||||
*/
|
||||
smp_store_release(&buf->tail->commit, buf->tail->used);
|
||||
tty_flip_buffer_commit(buf->tail);
|
||||
queue_work(system_unbound_wq, &buf->work);
|
||||
}
|
||||
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
|
||||
* @port: tty port to initialise
|
||||
|
@ -855,7 +855,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr)
|
||||
unsigned short *p = (unsigned short *) vc->vc_pos;
|
||||
|
||||
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,
|
||||
nr * 2);
|
||||
vc->vc_need_wrap = 0;
|
||||
|
@ -390,6 +390,11 @@ static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
|
||||
static inline int setup_earlycon(char *buf) { return 0; }
|
||||
#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 console *c);
|
||||
int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
|
||||
|
@ -38,8 +38,9 @@
|
||||
#define N_NULL 27 /* Null ldisc used for error handling */
|
||||
#define N_MCTP 28 /* MCTP-over-serial */
|
||||
#define N_DEVELOPMENT 29 /* Manual out-of-tree testing */
|
||||
#define N_CAN327 30 /* ELM327 based OBD-II interfaces */
|
||||
|
||||
/* Always the newest line discipline + 1 */
|
||||
#define NR_LDISCS 30
|
||||
#define NR_LDISCS 31
|
||||
|
||||
#endif /* _UAPI_LINUX_TTY_H */
|
||||
|
Loading…
Reference in New Issue
Block a user