Skip to content

Commit

Permalink
Merge tag 'tty-6.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/gregkh/tty

Pull tty / serial driver fixes from Greg KH:
 "Here are some small tty and serial driver fixes for reported problems
  for 6.11-rc3. Included in here are:

   - sc16is7xx serial driver fixes

   - uartclk bugfix for a divide by zero issue

   - conmakehash userspace build issue fix

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

* tag 'tty-6.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  tty: vt: conmakehash: cope with abs_srctree no longer in env
  serial: sc16is7xx: fix invalid FIFO access with special register set
  serial: sc16is7xx: fix TX fifo corruption
  serial: core: check uartclk for zero to avoid divide by zero
  • Loading branch information
Linus Torvalds committed Aug 11, 2024
2 parents 84e6da5 + 6e20753 commit 42b34a8
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 23 deletions.
25 changes: 15 additions & 10 deletions drivers/tty/serial/sc16is7xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ struct sc16is7xx_one {
struct kthread_work reg_work;
struct kthread_delayed_work ms_work;
struct sc16is7xx_one_config config;
unsigned char buf[SC16IS7XX_FIFO_SIZE]; /* Rx buffer. */
unsigned int old_mctrl;
u8 old_lcr; /* Value before EFR access. */
bool irda_mode;
Expand All @@ -340,7 +341,6 @@ struct sc16is7xx_port {
unsigned long gpio_valid_mask;
#endif
u8 mctrl_mask;
unsigned char buf[SC16IS7XX_FIFO_SIZE];
struct kthread_worker kworker;
struct task_struct *kworker_task;
struct sc16is7xx_one p[];
Expand Down Expand Up @@ -592,6 +592,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
SC16IS7XX_MCR_CLKSEL_BIT,
prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT);

mutex_lock(&one->efr_lock);

/* Backup LCR and access special register set (DLL/DLH) */
lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
Expand All @@ -606,24 +608,26 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
/* Restore LCR and access to general register set */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);

mutex_unlock(&one->efr_lock);

return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div);
}

static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
unsigned int iir)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
unsigned int lsr = 0, bytes_read, i;
bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC) ? true : false;
u8 ch, flag;

if (unlikely(rxlen >= sizeof(s->buf))) {
if (unlikely(rxlen >= sizeof(one->buf))) {
dev_warn_ratelimited(port->dev,
"ttySC%i: Possible RX FIFO overrun: %d\n",
port->line, rxlen);
port->icount.buf_overrun++;
/* Ensure sanity of RX level */
rxlen = sizeof(s->buf);
rxlen = sizeof(one->buf);
}

while (rxlen) {
Expand All @@ -636,10 +640,10 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
lsr = 0;

if (read_lsr) {
s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
one->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
bytes_read = 1;
} else {
sc16is7xx_fifo_read(port, s->buf, rxlen);
sc16is7xx_fifo_read(port, one->buf, rxlen);
bytes_read = rxlen;
}

Expand Down Expand Up @@ -672,7 +676,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
}

for (i = 0; i < bytes_read; ++i) {
ch = s->buf[i];
ch = one->buf[i];
if (uart_handle_sysrq_char(port, ch))
continue;

Expand All @@ -690,10 +694,10 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,

static void sc16is7xx_handle_tx(struct uart_port *port)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
struct tty_port *tport = &port->state->port;
unsigned long flags;
unsigned int txlen;
unsigned char *tail;

if (unlikely(port->x_char)) {
sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char);
Expand All @@ -718,8 +722,9 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
txlen = 0;
}

txlen = uart_fifo_out(port, s->buf, txlen);
sc16is7xx_fifo_write(port, s->buf, txlen);
txlen = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, txlen);
sc16is7xx_fifo_write(port, tail, txlen);
uart_xmit_advance(port, txlen);

uart_port_lock_irqsave(port, &flags);
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
Expand Down
8 changes: 8 additions & 0 deletions drivers/tty/serial/serial_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,14 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
new_flags = (__force upf_t)new_info->flags;
old_custom_divisor = uport->custom_divisor;

if (!(uport->flags & UPF_FIXED_PORT)) {
unsigned int uartclk = new_info->baud_base * 16;
/* check needs to be done here before other settings made */
if (uartclk == 0) {
retval = -EINVAL;
goto exit;
}
}
if (!capable(CAP_SYS_ADMIN)) {
retval = -EPERM;
if (change_irq || change_port ||
Expand Down
20 changes: 7 additions & 13 deletions drivers/tty/vt/conmakehash.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
* Copyright (C) 1995-1997 H. Peter Anvin
*/

#include <libgen.h>
#include <linux/limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sysexits.h>
Expand Down Expand Up @@ -76,8 +78,8 @@ static void addpair(int fp, int un)
int main(int argc, char *argv[])
{
FILE *ctbl;
const char *tblname, *rel_tblname;
const char *abs_srctree;
const char *tblname;
char base_tblname[PATH_MAX];
char buffer[65536];
int fontlen;
int i, nuni, nent;
Expand All @@ -102,16 +104,6 @@ int main(int argc, char *argv[])
}
}

abs_srctree = getenv("abs_srctree");
if (abs_srctree && !strncmp(abs_srctree, tblname, strlen(abs_srctree)))
{
rel_tblname = tblname + strlen(abs_srctree);
while (*rel_tblname == '/')
++rel_tblname;
}
else
rel_tblname = tblname;

/* For now we assume the default font is always 256 characters. */
fontlen = 256;

Expand Down Expand Up @@ -253,6 +245,8 @@ int main(int argc, char *argv[])
for ( i = 0 ; i < fontlen ; i++ )
nuni += unicount[i];

strncpy(base_tblname, tblname, PATH_MAX);
base_tblname[PATH_MAX - 1] = 0;
printf("\
/*\n\
* Do not edit this file; it was automatically generated by\n\
Expand All @@ -264,7 +258,7 @@ int main(int argc, char *argv[])
#include <linux/types.h>\n\
\n\
u8 dfont_unicount[%d] = \n\
{\n\t", rel_tblname, fontlen);
{\n\t", basename(base_tblname), fontlen);

for ( i = 0 ; i < fontlen ; i++ )
{
Expand Down

0 comments on commit 42b34a8

Please sign in to comment.