summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/amiserial.c14
-rw-r--r--drivers/tty/moxa.c169
-rw-r--r--drivers/tty/n_gsm.c2
-rw-r--r--drivers/tty/n_hdlc.c79
-rw-r--r--drivers/tty/n_tty.c109
-rw-r--r--drivers/tty/pty.c154
-rw-r--r--drivers/tty/serial/8250/8250.h13
-rw-r--r--drivers/tty/serial/8250/8250_core.c4
-rw-r--r--drivers/tty/serial/8250/8250_dw.c4
-rw-r--r--drivers/tty/serial/8250/8250_exar.c4
-rw-r--r--drivers/tty/serial/8250/8250_keba.c280
-rw-r--r--drivers/tty/serial/8250/8250_loongson.c238
-rw-r--r--drivers/tty/serial/8250/8250_of.c2
-rw-r--r--drivers/tty/serial/8250/8250_pci.c48
-rw-r--r--drivers/tty/serial/8250/8250_pci1xxxx.c10
-rw-r--r--drivers/tty/serial/8250/8250_pcilib.c7
-rw-r--r--drivers/tty/serial/8250/8250_pcilib.h2
-rw-r--r--drivers/tty/serial/8250/8250_platform.c57
-rw-r--r--drivers/tty/serial/8250/8250_rsa.c50
-rw-r--r--drivers/tty/serial/8250/Kconfig40
-rw-r--r--drivers/tty/serial/8250/Makefile4
-rw-r--r--drivers/tty/serial/Kconfig2
-rw-r--r--drivers/tty/serial/amba-pl011.c2
-rw-r--r--drivers/tty/serial/ar933x_uart.c62
-rw-r--r--drivers/tty/serial/fsl_lpuart.c8
-rw-r--r--drivers/tty/serial/icom.c9
-rw-r--r--drivers/tty/serial/imx.c24
-rw-r--r--drivers/tty/serial/jsm/jsm_driver.c1
-rw-r--r--drivers/tty/serial/kgdboc.c1
-rw-r--r--drivers/tty/serial/mux.c2
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c178
-rw-r--r--drivers/tty/serial/samsung_tty.c2
-rw-r--r--drivers/tty/serial/sc16is7xx.c413
-rw-r--r--drivers/tty/serial/sc16is7xx.h1
-rw-r--r--drivers/tty/serial/sc16is7xx_i2c.c4
-rw-r--r--drivers/tty/serial/sc16is7xx_spi.c4
-rw-r--r--drivers/tty/serial/serial_core.c168
-rw-r--r--drivers/tty/serial/sh-sci.c196
-rw-r--r--drivers/tty/serial/sh-sci.h178
-rw-r--r--drivers/tty/serial/sprd_serial.c6
-rw-r--r--drivers/tty/serial/xilinx_uartps.c15
-rw-r--r--drivers/tty/synclink_gt.c20
-rw-r--r--drivers/tty/tty_buffer.c8
-rw-r--r--drivers/tty/vt/keyboard.c318
-rw-r--r--drivers/tty/vt/selection.c9
-rw-r--r--drivers/tty/vt/vt.c4
46 files changed, 1720 insertions, 1205 deletions
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 5af46442a792..81eaca751541 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -438,7 +438,7 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id)
* ---------------------------------------------------------------
*/
-static int startup(struct tty_struct *tty, struct serial_state *info)
+static int rs_startup(struct tty_struct *tty, struct serial_state *info)
{
struct tty_port *port = &info->tport;
unsigned long flags;
@@ -513,7 +513,7 @@ errout:
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
-static void shutdown(struct tty_struct *tty, struct serial_state *info)
+static void rs_shutdown(struct tty_struct *tty, struct serial_state *info)
{
unsigned long flags;
@@ -975,7 +975,7 @@ check_and_exit:
change_speed(tty, state, NULL);
}
} else
- retval = startup(tty, state);
+ retval = rs_startup(tty, state);
tty_unlock(tty);
return retval;
}
@@ -1251,9 +1251,9 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
*/
rs_wait_until_sent(tty, state->timeout);
}
- shutdown(tty, state);
+ rs_shutdown(tty, state);
rs_flush_buffer(tty);
-
+
tty_ldisc_flush(tty);
port->tty = NULL;
@@ -1325,7 +1325,7 @@ static void rs_hangup(struct tty_struct *tty)
struct serial_state *info = tty->driver_data;
rs_flush_buffer(tty);
- shutdown(tty, info);
+ rs_shutdown(tty, info);
info->tport.count = 0;
tty_port_set_active(&info->tport, false);
info->tport.tty = NULL;
@@ -1349,7 +1349,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
port->tty = tty;
tty->driver_data = info;
- retval = startup(tty, info);
+ retval = rs_startup(tty, info);
if (retval) {
return retval;
}
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 329b30fac8fc..1bb2376af85c 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -487,25 +487,20 @@ static void moxa_wait_finish(void __iomem *ofsAddr)
static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
{
- unsigned long flags;
- spin_lock_irqsave(&moxafunc_lock, flags);
+ guard(spinlock_irqsave)(&moxafunc_lock);
writew(arg, ofsAddr + FuncArg);
writew(cmd, ofsAddr + FuncCode);
moxa_wait_finish(ofsAddr);
- spin_unlock_irqrestore(&moxafunc_lock, flags);
}
static int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg)
{
- unsigned long flags;
- u16 ret;
- spin_lock_irqsave(&moxafunc_lock, flags);
+ guard(spinlock_irqsave)(&moxafunc_lock);
writew(arg, ofsAddr + FuncArg);
writew(cmd, ofsAddr + FuncCode);
moxa_wait_finish(ofsAddr);
- ret = readw(ofsAddr + FuncArg);
- spin_unlock_irqrestore(&moxafunc_lock, flags);
- return ret;
+
+ return readw(ofsAddr + FuncArg);
}
static void moxa_low_water_check(void __iomem *ofsAddr)
@@ -1002,11 +997,11 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
if (ret)
goto err_free;
- spin_lock_bh(&moxa_lock);
- brd->ready = 1;
- if (!timer_pending(&moxaTimer))
- mod_timer(&moxaTimer, jiffies + HZ / 50);
- spin_unlock_bh(&moxa_lock);
+ scoped_guard(spinlock_bh, &moxa_lock) {
+ brd->ready = 1;
+ if (!timer_pending(&moxaTimer))
+ mod_timer(&moxaTimer, jiffies + HZ / 50);
+ }
first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
for (i = 0; i < brd->numPorts; i++)
@@ -1026,29 +1021,29 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
{
unsigned int a, opened, first_idx;
- mutex_lock(&moxa_openlock);
- spin_lock_bh(&moxa_lock);
- brd->ready = 0;
- spin_unlock_bh(&moxa_lock);
-
- /* pci hot-un-plug support */
- for (a = 0; a < brd->numPorts; a++)
- if (tty_port_initialized(&brd->ports[a].port))
- tty_port_tty_hangup(&brd->ports[a].port, false);
-
- for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
- tty_port_destroy(&brd->ports[a].port);
+ scoped_guard(mutex, &moxa_openlock) {
+ scoped_guard(spinlock_bh, &moxa_lock)
+ brd->ready = 0;
- while (1) {
- opened = 0;
+ /* pci hot-un-plug support */
for (a = 0; a < brd->numPorts; a++)
if (tty_port_initialized(&brd->ports[a].port))
- opened++;
- mutex_unlock(&moxa_openlock);
- if (!opened)
- break;
- msleep(50);
- mutex_lock(&moxa_openlock);
+ tty_port_tty_hangup(&brd->ports[a].port, false);
+
+ for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
+ tty_port_destroy(&brd->ports[a].port);
+
+ while (1) {
+ opened = 0;
+ for (a = 0; a < brd->numPorts; a++)
+ if (tty_port_initialized(&brd->ports[a].port))
+ opened++;
+ if (!opened)
+ break;
+ mutex_unlock(&moxa_openlock);
+ msleep(50);
+ mutex_lock(&moxa_openlock);
+ }
}
first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
@@ -1206,12 +1201,9 @@ static void moxa_shutdown(struct tty_port *port)
static bool moxa_carrier_raised(struct tty_port *port)
{
struct moxa_port *ch = container_of(port, struct moxa_port, port);
- int dcd;
- spin_lock_irq(&port->lock);
- dcd = ch->DCDState;
- spin_unlock_irq(&port->lock);
- return dcd;
+ guard(spinlock_irq)(&port->lock);
+ return ch->DCDState;
}
static void moxa_dtr_rts(struct tty_port *port, bool active)
@@ -1225,37 +1217,31 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
{
struct moxa_board_conf *brd;
struct moxa_port *ch;
- int port;
-
- port = tty->index;
- if (mutex_lock_interruptible(&moxa_openlock))
- return -ERESTARTSYS;
- brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
- if (!brd->ready) {
- mutex_unlock(&moxa_openlock);
- return -ENODEV;
- }
+ int port = tty->index;
- if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) {
- mutex_unlock(&moxa_openlock);
- return -ENODEV;
- }
-
- ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
- ch->port.count++;
- tty->driver_data = ch;
- tty_port_tty_set(&ch->port, tty);
- mutex_lock(&ch->port.mutex);
- if (!tty_port_initialized(&ch->port)) {
- ch->statusflags = 0;
- moxa_set_tty_param(tty, &tty->termios);
- MoxaPortLineCtrl(ch, true, true);
- MoxaPortEnable(ch);
- MoxaSetFifo(ch, ch->type == PORT_16550A);
- tty_port_set_initialized(&ch->port, true);
+ scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &moxa_openlock) {
+ brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
+ if (!brd->ready)
+ return -ENODEV;
+
+ if (port % MAX_PORTS_PER_BOARD >= brd->numPorts)
+ return -ENODEV;
+
+ ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
+ ch->port.count++;
+ tty->driver_data = ch;
+ tty_port_tty_set(&ch->port, tty);
+
+ guard(mutex)(&ch->port.mutex);
+ if (!tty_port_initialized(&ch->port)) {
+ ch->statusflags = 0;
+ moxa_set_tty_param(tty, &tty->termios);
+ MoxaPortLineCtrl(ch, true, true);
+ MoxaPortEnable(ch);
+ MoxaSetFifo(ch, ch->type == PORT_16550A);
+ tty_port_set_initialized(&ch->port, true);
+ }
}
- mutex_unlock(&ch->port.mutex);
- mutex_unlock(&moxa_openlock);
return tty_port_block_til_ready(&ch->port, tty, filp);
}
@@ -1270,15 +1256,13 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
static ssize_t moxa_write(struct tty_struct *tty, const u8 *buf, size_t count)
{
struct moxa_port *ch = tty->driver_data;
- unsigned long flags;
int len;
if (ch == NULL)
return 0;
- spin_lock_irqsave(&moxa_lock, flags);
- len = MoxaPortWriteData(tty, buf, count);
- spin_unlock_irqrestore(&moxa_lock, flags);
+ scoped_guard(spinlock_irqsave, &moxa_lock)
+ len = MoxaPortWriteData(tty, buf, count);
set_bit(LOWWAIT, &ch->statusflags);
return len;
@@ -1349,12 +1333,10 @@ static int moxa_tiocmset(struct tty_struct *tty,
bool dtr_active, rts_active;
struct moxa_port *ch;
- mutex_lock(&moxa_openlock);
+ guard(mutex)(&moxa_openlock);
ch = tty->driver_data;
- if (!ch) {
- mutex_unlock(&moxa_openlock);
+ if (!ch)
return -EINVAL;
- }
MoxaPortGetLineOut(ch, &dtr_active, &rts_active);
if (set & TIOCM_RTS)
@@ -1366,7 +1348,7 @@ static int moxa_tiocmset(struct tty_struct *tty,
if (clear & TIOCM_DTR)
dtr_active = false;
MoxaPortLineCtrl(ch, dtr_active, rts_active);
- mutex_unlock(&moxa_openlock);
+
return 0;
}
@@ -1415,18 +1397,17 @@ static void moxa_hangup(struct tty_struct *tty)
static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
{
- unsigned long flags;
dcd = !!dcd;
- spin_lock_irqsave(&p->port.lock, flags);
- if (dcd != p->DCDState) {
- p->DCDState = dcd;
- spin_unlock_irqrestore(&p->port.lock, flags);
- if (!dcd)
- tty_port_tty_hangup(&p->port, true);
+ scoped_guard(spinlock_irqsave, &p->port.lock) {
+ if (dcd == p->DCDState)
+ return;
+
+ p->DCDState = dcd;
}
- else
- spin_unlock_irqrestore(&p->port.lock, flags);
+
+ if (!dcd)
+ tty_port_tty_hangup(&p->port, true);
}
static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
@@ -1494,7 +1475,7 @@ static void moxa_poll(struct timer_list *unused)
u16 __iomem *ip;
unsigned int card, port, served = 0;
- spin_lock(&moxa_lock);
+ guard(spinlock)(&moxa_lock);
for (card = 0; card < MAX_BOARDS; card++) {
brd = &moxa_boards[card];
if (!brd->ready)
@@ -1525,7 +1506,6 @@ static void moxa_poll(struct timer_list *unused)
if (served)
mod_timer(&moxaTimer, jiffies + HZ / 50);
- spin_unlock(&moxa_lock);
}
/******************************************************************************/
@@ -1861,13 +1841,11 @@ static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
baud = MoxaPortSetBaud(port, baud);
if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
- spin_lock_irq(&moxafunc_lock);
+ guard(spinlock_irq)(&moxafunc_lock);
writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
writeb(FC_SetXonXoff, ofsAddr + FuncCode);
moxa_wait_finish(ofsAddr);
- spin_unlock_irq(&moxafunc_lock);
-
}
return baud;
}
@@ -2098,13 +2076,13 @@ static int moxa_get_serial_info(struct tty_struct *tty,
if (!info)
return -ENODEV;
- mutex_lock(&info->port.mutex);
+ guard(mutex)(&info->port.mutex);
ss->type = info->type;
ss->line = info->port.tty->index;
ss->flags = info->port.flags;
ss->baud_base = 921600;
ss->close_delay = jiffies_to_msecs(info->port.close_delay) / 10;
- mutex_unlock(&info->port.mutex);
+
return 0;
}
@@ -2120,13 +2098,12 @@ static int moxa_set_serial_info(struct tty_struct *tty,
close_delay = msecs_to_jiffies(ss->close_delay * 10);
- mutex_lock(&info->port.mutex);
+ guard(mutex)(&info->port.mutex);
if (!capable(CAP_SYS_ADMIN)) {
if (close_delay != info->port.close_delay ||
ss->type != info->type ||
((ss->flags & ~ASYNC_USR_MASK) !=
(info->port.flags & ~ASYNC_USR_MASK))) {
- mutex_unlock(&info->port.mutex);
return -EPERM;
}
} else {
@@ -2136,7 +2113,7 @@ static int moxa_set_serial_info(struct tty_struct *tty,
info->type = ss->type;
}
- mutex_unlock(&info->port.mutex);
+
return 0;
}
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 553d8c70352b..214abeb89aaa 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -4165,7 +4165,7 @@ static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
/**
* gsm_modem_send_initial_msc - Send initial modem status message
*
- * @dlci channel
+ * @dlci: channel
*
* Send an initial MSC message after DLCI open to set the initial
* modem status lines. This is only done for basic mode.
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index 4a4dc58b866a..3c9dcb0928c6 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -263,21 +263,18 @@ static int n_hdlc_tty_open(struct tty_struct *tty)
*/
static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
{
- unsigned long flags;
struct n_hdlc_buf *tbuf;
ssize_t actual;
check_again:
-
- spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
- if (n_hdlc->tbusy) {
- n_hdlc->woke_up = true;
- spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
- return;
+ scoped_guard(spinlock_irqsave, &n_hdlc->tx_buf_list.spinlock) {
+ if (n_hdlc->tbusy) {
+ n_hdlc->woke_up = true;
+ return;
+ }
+ n_hdlc->tbusy = true;
+ n_hdlc->woke_up = false;
}
- n_hdlc->tbusy = true;
- n_hdlc->woke_up = false;
- spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
while (tbuf) {
@@ -324,9 +321,8 @@ check_again:
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
/* Clear the re-entry flag */
- spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
- n_hdlc->tbusy = false;
- spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+ scoped_guard(spinlock_irqsave, &n_hdlc->tx_buf_list.spinlock)
+ n_hdlc->tbusy = false;
if (n_hdlc->woke_up)
goto check_again;
@@ -584,9 +580,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
unsigned long arg)
{
struct n_hdlc *n_hdlc = tty->disc_data;
- int error = 0;
int count;
- unsigned long flags;
struct n_hdlc_buf *buf = NULL;
pr_debug("%s() called %d\n", __func__, cmd);
@@ -595,29 +589,27 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
case FIONREAD:
/* report count of read data available */
/* in next available frame (if any) */
- spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock, flags);
- buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list,
- struct n_hdlc_buf, list_item);
- if (buf)
- count = buf->count;
- else
- count = 0;
- spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock, flags);
- error = put_user(count, (int __user *)arg);
- break;
+ scoped_guard(spinlock_irqsave, &n_hdlc->rx_buf_list.spinlock) {
+ buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list,
+ struct n_hdlc_buf, list_item);
+ if (buf)
+ count = buf->count;
+ else
+ count = 0;
+ }
+ return put_user(count, (int __user *)arg);
case TIOCOUTQ:
/* get the pending tx byte count in the driver */
count = tty_chars_in_buffer(tty);
/* add size of next output frame in queue */
- spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
- buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list,
- struct n_hdlc_buf, list_item);
- if (buf)
- count += buf->count;
- spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
- error = put_user(count, (int __user *)arg);
- break;
+ scoped_guard(spinlock_irqsave, &n_hdlc->tx_buf_list.spinlock) {
+ buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list,
+ struct n_hdlc_buf, list_item);
+ if (buf)
+ count += buf->count;
+ }
+ return put_user(count, (int __user *)arg);
case TCFLSH:
switch (arg) {
@@ -628,11 +620,8 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
fallthrough; /* to default */
default:
- error = n_tty_ioctl_helper(tty, cmd, arg);
- break;
+ return n_tty_ioctl_helper(tty, cmd, arg);
}
- return error;
-
} /* end of n_hdlc_tty_ioctl() */
/**
@@ -726,14 +715,10 @@ static struct n_hdlc *n_hdlc_alloc(void)
static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
struct n_hdlc_buf *buf)
{
- unsigned long flags;
-
- spin_lock_irqsave(&buf_list->spinlock, flags);
+ guard(spinlock_irqsave)(&buf_list->spinlock);
list_add(&buf->list_item, &buf_list->list);
buf_list->count++;
-
- spin_unlock_irqrestore(&buf_list->spinlock, flags);
}
/**
@@ -744,14 +729,10 @@ static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list,
struct n_hdlc_buf *buf)
{
- unsigned long flags;
-
- spin_lock_irqsave(&buf_list->spinlock, flags);
+ guard(spinlock_irqsave)(&buf_list->spinlock);
list_add_tail(&buf->list_item, &buf_list->list);
buf_list->count++;
-
- spin_unlock_irqrestore(&buf_list->spinlock, flags);
} /* end of n_hdlc_buf_put() */
/**
@@ -764,10 +745,9 @@ static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list,
*/
static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
{
- unsigned long flags;
struct n_hdlc_buf *buf;
- spin_lock_irqsave(&buf_list->spinlock, flags);
+ guard(spinlock_irqsave)(&buf_list->spinlock);
buf = list_first_entry_or_null(&buf_list->list,
struct n_hdlc_buf, list_item);
@@ -776,7 +756,6 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
buf_list->count--;
}
- spin_unlock_irqrestore(&buf_list->spinlock, flags);
return buf;
} /* end of n_hdlc_buf_get() */
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 6af3f3a0b531..e6a0f5b40d0a 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -324,12 +324,9 @@ static void reset_buffer_flags(struct n_tty_data *ldata)
static void n_tty_packet_mode_flush(struct tty_struct *tty)
{
- unsigned long flags;
-
if (tty->link->ctrl.packet) {
- spin_lock_irqsave(&tty->ctrl.lock, flags);
- tty->ctrl.pktstatus |= TIOCPKT_FLUSHREAD;
- spin_unlock_irqrestore(&tty->ctrl.lock, flags);
+ scoped_guard(spinlock_irqsave, &tty->ctrl.lock)
+ tty->ctrl.pktstatus |= TIOCPKT_FLUSHREAD;
wake_up_interruptible(&tty->link->read_wait);
}
}
@@ -349,13 +346,12 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty)
*/
static void n_tty_flush_buffer(struct tty_struct *tty)
{
- down_write(&tty->termios_rwsem);
+ guard(rwsem_write)(&tty->termios_rwsem);
reset_buffer_flags(tty->disc_data);
n_tty_kick_worker(tty);
if (tty->link)
n_tty_packet_mode_flush(tty);
- up_write(&tty->termios_rwsem);
}
/**
@@ -737,24 +733,22 @@ static void commit_echoes(struct tty_struct *tty)
size_t nr, old, echoed;
size_t head;
- mutex_lock(&ldata->output_lock);
- head = ldata->echo_head;
- ldata->echo_mark = head;
- old = ldata->echo_commit - ldata->echo_tail;
-
- /* Process committed echoes if the accumulated # of bytes
- * is over the threshold (and try again each time another
- * block is accumulated) */
- nr = head - ldata->echo_tail;
- if (nr < ECHO_COMMIT_WATERMARK ||
- (nr % ECHO_BLOCK > old % ECHO_BLOCK)) {
- mutex_unlock(&ldata->output_lock);
- return;
- }
+ scoped_guard(mutex, &ldata->output_lock) {
+ head = ldata->echo_head;
+ ldata->echo_mark = head;
+ old = ldata->echo_commit - ldata->echo_tail;
+
+ /*
+ * Process committed echoes if the accumulated # of bytes is over the threshold
+ * (and try again each time another block is accumulated)
+ */
+ nr = head - ldata->echo_tail;
+ if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK))
+ return;
- ldata->echo_commit = head;
- echoed = __process_echoes(tty);
- mutex_unlock(&ldata->output_lock);
+ ldata->echo_commit = head;
+ echoed = __process_echoes(tty);
+ }
if (echoed && tty->ops->flush_chars)
tty->ops->flush_chars(tty);
@@ -768,10 +762,10 @@ static void process_echoes(struct tty_struct *tty)
if (ldata->echo_mark == ldata->echo_tail)
return;
- mutex_lock(&ldata->output_lock);
- ldata->echo_commit = ldata->echo_mark;
- echoed = __process_echoes(tty);
- mutex_unlock(&ldata->output_lock);
+ scoped_guard(mutex, &ldata->output_lock) {
+ ldata->echo_commit = ldata->echo_mark;
+ echoed = __process_echoes(tty);
+ }
if (echoed && tty->ops->flush_chars)
tty->ops->flush_chars(tty);
@@ -786,10 +780,9 @@ static void flush_echoes(struct tty_struct *tty)
ldata->echo_commit == ldata->echo_head)
return;
- mutex_lock(&ldata->output_lock);
+ guard(mutex)(&ldata->output_lock);
ldata->echo_commit = ldata->echo_head;
__process_echoes(tty);
- mutex_unlock(&ldata->output_lock);
}
/**
@@ -1078,18 +1071,19 @@ static void isig(int sig, struct tty_struct *tty)
if (L_NOFLSH(tty)) {
/* signal only */
__isig(sig, tty);
+ return;
+ }
- } else { /* signal and flush */
- up_read(&tty->termios_rwsem);
- down_write(&tty->termios_rwsem);
-
+ /* signal and flush */
+ up_read(&tty->termios_rwsem);
+ scoped_guard(rwsem_write, &tty->termios_rwsem) {
__isig(sig, tty);
/* clear echo buffer */
- mutex_lock(&ldata->output_lock);
- ldata->echo_head = ldata->echo_tail = 0;
- ldata->echo_mark = ldata->echo_commit = 0;
- mutex_unlock(&ldata->output_lock);
+ scoped_guard(mutex, &ldata->output_lock) {
+ ldata->echo_head = ldata->echo_tail = 0;
+ ldata->echo_mark = ldata->echo_commit = 0;
+ }
/* clear output buffer */
tty_driver_flush_buffer(tty);
@@ -1100,10 +1094,8 @@ static void isig(int sig, struct tty_struct *tty)
/* notify pty master of flush */
if (tty->link)
n_tty_packet_mode_flush(tty);
-
- up_write(&tty->termios_rwsem);
- down_read(&tty->termios_rwsem);
}
+ down_read(&tty->termios_rwsem);
}
/**
@@ -1683,7 +1675,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const u8 *cp, const u8 *fp,
size_t n, rcvd = 0;
int room, overflow;
- down_read(&tty->termios_rwsem);
+ guard(rwsem_read)(&tty->termios_rwsem);
do {
/*
@@ -1752,8 +1744,6 @@ n_tty_receive_buf_common(struct tty_struct *tty, const u8 *cp, const u8 *fp,
n_tty_kick_worker(tty);
}
- up_read(&tty->termios_rwsem);
-
return rcvd;
}
@@ -1879,10 +1869,9 @@ static void n_tty_close(struct tty_struct *tty)
if (tty->link)
n_tty_packet_mode_flush(tty);
- down_write(&tty->termios_rwsem);
+ guard(rwsem_write)(&tty->termios_rwsem);
vfree(ldata);
tty->disc_data = NULL;
- up_write(&tty->termios_rwsem);
}
/**
@@ -2247,10 +2236,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf,
u8 cs;
if (kb != kbuf)
break;
- spin_lock_irq(&tty->link->ctrl.lock);
- cs = tty->link->ctrl.pktstatus;
- tty->link->ctrl.pktstatus = 0;
- spin_unlock_irq(&tty->link->ctrl.lock);
+ scoped_guard(spinlock_irq, &tty->link->ctrl.lock) {
+ cs = tty->link->ctrl.pktstatus;
+ tty->link->ctrl.pktstatus = 0;
+ }
*kb++ = cs;
nr--;
break;
@@ -2357,7 +2346,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
return retval;
}
- down_read(&tty->termios_rwsem);
+ guard(rwsem_read)(&tty->termios_rwsem);
/* Write out any echoed characters that are still pending */
process_echoes(tty);
@@ -2395,9 +2384,8 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
struct n_tty_data *ldata = tty->disc_data;
while (nr > 0) {
- mutex_lock(&ldata->output_lock);
- num = tty->ops->write(tty, b, nr);
- mutex_unlock(&ldata->output_lock);
+ scoped_guard(mutex, &ldata->output_lock)
+ num = tty->ops->write(tty, b, nr);
if (num < 0) {
retval = num;
goto break_out;
@@ -2424,7 +2412,7 @@ break_out:
remove_wait_queue(&tty->write_wait, &wait);
if (nr && tty->fasync)
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- up_read(&tty->termios_rwsem);
+
return (b - buf) ? b - buf : retval;
}
@@ -2498,12 +2486,11 @@ static int n_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
case TIOCOUTQ:
return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
case TIOCINQ:
- down_write(&tty->termios_rwsem);
- if (L_ICANON(tty) && !L_EXTPROC(tty))
- num = inq_canon(ldata);
- else
- num = read_cnt(ldata);
- up_write(&tty->termios_rwsem);
+ scoped_guard(rwsem_write, &tty->termios_rwsem)
+ if (L_ICANON(tty) && !L_EXTPROC(tty))
+ num = inq_canon(ldata);
+ else
+ num = read_cnt(ldata);
return put_user(num, (unsigned int __user *) arg);
default:
return n_tty_ioctl_helper(tty, cmd, arg);
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 8bb1a01fef2a..6120d827a797 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -57,9 +57,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
set_bit(TTY_IO_ERROR, &tty->flags);
wake_up_interruptible(&tty->read_wait);
wake_up_interruptible(&tty->write_wait);
- spin_lock_irq(&tty->ctrl.lock);
- tty->ctrl.packet = false;
- spin_unlock_irq(&tty->ctrl.lock);
+ scoped_guard(spinlock_irq, &tty->ctrl.lock)
+ tty->ctrl.packet = false;
/* Review - krefs on tty_link ?? */
if (!tty->link)
return;
@@ -70,10 +69,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
set_bit(TTY_OTHER_CLOSED, &tty->flags);
#ifdef CONFIG_UNIX98_PTYS
if (tty->driver == ptm_driver) {
- mutex_lock(&devpts_mutex);
+ guard(mutex)(&devpts_mutex);
if (tty->link->driver_data)
devpts_pty_kill(tty->link->driver_data);
- mutex_unlock(&devpts_mutex);
}
#endif
tty_vhangup(tty->link);
@@ -157,21 +155,23 @@ static int pty_get_lock(struct tty_struct *tty, int __user *arg)
/* Set the packet mode on a pty */
static int pty_set_pktmode(struct tty_struct *tty, int __user *arg)
{
- int pktmode;
+ int want_pktmode;
- if (get_user(pktmode, arg))
+ if (get_user(want_pktmode, arg))
return -EFAULT;
- spin_lock_irq(&tty->ctrl.lock);
- if (pktmode) {
- if (!tty->ctrl.packet) {
- tty->link->ctrl.pktstatus = 0;
- smp_mb();
- tty->ctrl.packet = true;
- }
- } else
+ guard(spinlock_irq)(&tty->ctrl.lock);
+ if (!want_pktmode) {
tty->ctrl.packet = false;
- spin_unlock_irq(&tty->ctrl.lock);
+ return 0;
+ }
+
+ if (tty->ctrl.packet)
+ return 0;
+
+ tty->link->ctrl.pktstatus = 0;
+ smp_mb();
+ tty->ctrl.packet = true;
return 0;
}
@@ -210,10 +210,9 @@ static void pty_flush_buffer(struct tty_struct *tty)
tty_buffer_flush(to, NULL);
if (to->ctrl.packet) {
- spin_lock_irq(&tty->ctrl.lock);
+ guard(spinlock_irq)(&tty->ctrl.lock);
tty->ctrl.pktstatus |= TIOCPKT_FLUSHWRITE;
wake_up_interruptible(&to->read_wait);
- spin_unlock_irq(&tty->ctrl.lock);
}
}
@@ -252,17 +251,17 @@ static void pty_set_termios(struct tty_struct *tty,
STOP_CHAR(tty) == '\023' &&
START_CHAR(tty) == '\021');
if ((old_flow != new_flow) || extproc) {
- spin_lock_irq(&tty->ctrl.lock);
- if (old_flow != new_flow) {
- tty->ctrl.pktstatus &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
- if (new_flow)
- tty->ctrl.pktstatus |= TIOCPKT_DOSTOP;
- else
- tty->ctrl.pktstatus |= TIOCPKT_NOSTOP;
+ scoped_guard(spinlock_irq, &tty->ctrl.lock) {
+ if (old_flow != new_flow) {
+ tty->ctrl.pktstatus &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
+ if (new_flow)
+ tty->ctrl.pktstatus |= TIOCPKT_DOSTOP;
+ else
+ tty->ctrl.pktstatus |= TIOCPKT_NOSTOP;
+ }
+ if (extproc)
+ tty->ctrl.pktstatus |= TIOCPKT_IOCTL;
}
- if (extproc)
- tty->ctrl.pktstatus |= TIOCPKT_IOCTL;
- spin_unlock_irq(&tty->ctrl.lock);
wake_up_interruptible(&tty->link->read_wait);
}
}
@@ -286,9 +285,9 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws)
struct tty_struct *pty = tty->link;
/* For a PTY we need to lock the tty side */
- mutex_lock(&tty->winsize_mutex);
+ guard(mutex)(&tty->winsize_mutex);
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
- goto done;
+ return 0;
/* Signal the foreground process group of both ptys */
pgrp = tty_get_pgrp(tty);
@@ -304,8 +303,7 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws)
tty->winsize = *ws;
pty->winsize = *ws; /* Never used so will go away soon */
-done:
- mutex_unlock(&tty->winsize_mutex);
+
return 0;
}
@@ -321,28 +319,26 @@ done:
*/
static void pty_start(struct tty_struct *tty)
{
- unsigned long flags;
+ if (!tty->link || !tty->link->ctrl.packet)
+ return;
- if (tty->link && tty->link->ctrl.packet) {
- spin_lock_irqsave(&tty->ctrl.lock, flags);
+ scoped_guard(spinlock_irqsave, &tty->ctrl.lock) {
tty->ctrl.pktstatus &= ~TIOCPKT_STOP;
tty->ctrl.pktstatus |= TIOCPKT_START;
- spin_unlock_irqrestore(&tty->ctrl.lock, flags);
- wake_up_interruptible_poll(&tty->link->read_wait, EPOLLIN);
}
+ wake_up_interruptible_poll(&tty->link->read_wait, EPOLLIN);
}
static void pty_stop(struct tty_struct *tty)
{
- unsigned long flags;
+ if (!tty->link || !tty->link->ctrl.packet)
+ return;
- if (tty->link && tty->link->ctrl.packet) {
- spin_lock_irqsave(&tty->ctrl.lock, flags);
+ scoped_guard(spinlock_irqsave, &tty->ctrl.lock) {
tty->ctrl.pktstatus &= ~TIOCPKT_START;
tty->ctrl.pktstatus |= TIOCPKT_STOP;
- spin_unlock_irqrestore(&tty->ctrl.lock, flags);
- wake_up_interruptible_poll(&tty->link->read_wait, EPOLLIN);
}
+ wake_up_interruptible_poll(&tty->link->read_wait, EPOLLIN);
}
/**
@@ -589,6 +585,23 @@ static inline void legacy_pty_init(void) { }
#ifdef CONFIG_UNIX98_PTYS
static struct cdev ptmx_cdev;
+static struct file *ptm_open_peer_file(struct file *master,
+ struct tty_struct *tty, int flags)
+{
+ struct path path;
+ struct file *file;
+
+ /* Compute the slave's path */
+ path.mnt = devpts_mntget(master, tty->driver_data);
+ if (IS_ERR(path.mnt))
+ return ERR_CAST(path.mnt);
+ path.dentry = tty->link->driver_data;
+
+ file = dentry_open(&path, flags, current_cred());
+ mntput(path.mnt);
+ return file;
+}
+
/**
* ptm_open_peer - open the peer of a pty
* @master: the open struct file of the ptmx device node
@@ -601,42 +614,10 @@ static struct cdev ptmx_cdev;
*/
int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
{
- int fd;
- struct file *filp;
- int retval = -EINVAL;
- struct path path;
-
if (tty->driver != ptm_driver)
return -EIO;
- fd = get_unused_fd_flags(flags);
- if (fd < 0) {
- retval = fd;
- goto err;
- }
-
- /* Compute the slave's path */
- path.mnt = devpts_mntget(master, tty->driver_data);
- if (IS_ERR(path.mnt)) {
- retval = PTR_ERR(path.mnt);
- goto err_put;
- }
- path.dentry = tty->link->driver_data;
-
- filp = dentry_open(&path, flags, current_cred());
- mntput(path.mnt);
- if (IS_ERR(filp)) {
- retval = PTR_ERR(filp);
- goto err_put;
- }
-
- fd_install(fd, filp);
- return fd;
-
-err_put:
- put_unused_fd(fd);
-err:
- return retval;
+ return FD_ADD(flags, ptm_open_peer_file(master, tty, flags));
}
static int pty_unix98_ioctl(struct tty_struct *tty,
@@ -705,15 +686,9 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
struct file *file, int idx)
{
- struct tty_struct *tty;
-
- mutex_lock(&devpts_mutex);
- tty = devpts_get_priv(file->f_path.dentry);
- mutex_unlock(&devpts_mutex);
+ guard(mutex)(&devpts_mutex);
/* Master must be open before slave */
- if (!tty)
- return ERR_PTR(-EIO);
- return tty;
+ return devpts_get_priv(file->f_path.dentry) ? : ERR_PTR(-EIO);
}
static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
@@ -811,20 +786,17 @@ static int ptmx_open(struct inode *inode, struct file *filp)
}
/* find a device that is not in use. */
- mutex_lock(&devpts_mutex);
- index = devpts_new_index(fsi);
- mutex_unlock(&devpts_mutex);
+ scoped_guard(mutex, &devpts_mutex)
+ index = devpts_new_index(fsi);
retval = index;
if (index < 0)
goto out_put_fsi;
- mutex_lock(&tty_mutex);
- tty = tty_init_dev(ptm_driver, index);
- /* The tty returned here is locked so we can safely
- drop the mutex */
- mutex_unlock(&tty_mutex);
+ /* The tty returned here is locked so we can safely drop the mutex */
+ scoped_guard(mutex, &tty_mutex)
+ tty = tty_init_dev(ptm_driver, index);
retval = PTR_ERR(tty);
if (IS_ERR(tty))
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 58e64c4e1e3a..8caecfc85d93 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -98,15 +98,6 @@ struct serial8250_config {
extern unsigned int nr_uarts;
-#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
-#define SERIAL8250_SHARE_IRQS 1
-#else
-#define SERIAL8250_SHARE_IRQS 0
-#endif
-
-extern unsigned int share_irqs;
-extern unsigned int skip_txen_test;
-
#define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \
{ \
.iobase = _base, \
@@ -322,13 +313,13 @@ static inline void serial8250_pnp_exit(void) { }
#endif
#ifdef CONFIG_SERIAL_8250_RSA
-void univ8250_rsa_support(struct uart_ops *ops);
+void univ8250_rsa_support(struct uart_ops *ops, const struct uart_ops *core_ops);
void rsa_enable(struct uart_8250_port *up);
void rsa_disable(struct uart_8250_port *up);
void rsa_autoconfig(struct uart_8250_port *up);
void rsa_reset(struct uart_8250_port *up);
#else
-static inline void univ8250_rsa_support(struct uart_ops *ops) { }
+static inline void univ8250_rsa_support(struct uart_ops *ops, const struct uart_ops *core_ops) { }
static inline void rsa_enable(struct uart_8250_port *up) {}
static inline void rsa_disable(struct uart_8250_port *up) {}
static inline void rsa_autoconfig(struct uart_8250_port *up) {}
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index bfa421ab3253..0e81f78c6063 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -52,6 +52,10 @@ struct irq_info {
static DEFINE_HASHTABLE(irq_lists, IRQ_HASH_BITS);
static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */
+static bool skip_txen_test;
+module_param(skip_txen_test, bool, 0644);
+MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
+
/*
* This is the serial driver's interrupt routine.
*
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 710ae4d40aec..27af83f0ff46 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -361,7 +361,7 @@ static int dw8250_clk_notifier_cb(struct notifier_block *nb,
* deferred event handling complication.
*/
if (event == POST_RATE_CHANGE) {
- queue_work(system_unbound_wq, &d->clk_work);
+ queue_work(system_dfl_wq, &d->clk_work);
return NOTIFY_OK;
}
@@ -680,7 +680,7 @@ static int dw8250_probe(struct platform_device *pdev)
err = clk_notifier_register(data->clk, &data->clk_notifier);
if (err)
return dev_err_probe(dev, err, "Failed to set the clock notifier\n");
- queue_work(system_unbound_wq, &data->clk_work);
+ queue_work(system_dfl_wq, &data->clk_work);
}
platform_set_drvdata(pdev, data);
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index b9cc0b786ca6..c682c0d0dffa 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -505,7 +505,7 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev,
unsigned char status;
int err;
- err = serial8250_pci_setup_port(pcidev, port, 0, offset, board->reg_shift);
+ err = serial8250_pci_setup_port(pcidev, port, 0, offset, board->reg_shift, priv->virt);
if (err)
return err;
@@ -833,7 +833,7 @@ static int cti_port_setup_common(struct exar8250 *priv,
port->port.port_id = idx;
port->port.uartclk = priv->osc_freq;
- ret = serial8250_pci_setup_port(pcidev, port, 0, offset, 0);
+ ret = serial8250_pci_setup_port(pcidev, port, 0, offset, 0, priv->virt);
if (ret)
return ret;
diff --git a/drivers/tty/serial/8250/8250_keba.c b/drivers/tty/serial/8250/8250_keba.c
new file mode 100644
index 000000000000..c05b89551b12
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_keba.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 KEBA Industrial Automation GmbH
+ *
+ * Driver for KEBA UART FPGA IP core
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/misc/keba.h>
+#include <linux/module.h>
+
+#include "8250.h"
+
+#define KUART "kuart"
+
+/* flags */
+#define KUART_RS485 BIT(0)
+#define KUART_USE_CAPABILITY BIT(1)
+
+/* registers */
+#define KUART_VERSION 0x0000
+#define KUART_REVISION 0x0001
+#define KUART_CAPABILITY 0x0002
+#define KUART_CONTROL 0x0004
+#define KUART_BASE 0x000C
+#define KUART_REGSHIFT 2
+#define KUART_CLK 1843200
+
+/* mode flags */
+enum kuart_mode {
+ KUART_MODE_NONE = 0,
+ KUART_MODE_RS485,
+ KUART_MODE_RS422,
+ KUART_MODE_RS232
+};
+
+/* capability flags */
+#define KUART_CAPABILITY_NONE BIT(KUART_MODE_NONE)
+#define KUART_CAPABILITY_RS485 BIT(KUART_MODE_RS485)
+#define KUART_CAPABILITY_RS422 BIT(KUART_MODE_RS422)
+#define KUART_CAPABILITY_RS232 BIT(KUART_MODE_RS232)
+#define KUART_CAPABILITY_MASK GENMASK(3, 0)
+
+/* Additional Control Register DTR line configuration */
+#define UART_ACR_DTRLC_MASK 0x18
+#define UART_ACR_DTRLC_COMPAT 0x00
+#define UART_ACR_DTRLC_ENABLE_LOW 0x10
+
+struct kuart {
+ struct keba_uart_auxdev *auxdev;
+ void __iomem *base;
+ unsigned int line;
+
+ unsigned int flags;
+ u8 capability;
+ enum kuart_mode mode;
+};
+
+static void kuart_set_phy_mode(struct kuart *kuart, enum kuart_mode mode)
+{
+ iowrite8(mode, kuart->base + KUART_CONTROL);
+}
+
+static void kuart_enhanced_mode(struct uart_8250_port *up, bool enable)
+{
+ u8 lcr, efr;
+
+ /* backup LCR register */
+ lcr = serial_in(up, UART_LCR);
+
+ /* enable 650 compatible register set (EFR, ...) */
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+ /* enable/disable enhanced mode with indexed control registers */
+ efr = serial_in(up, UART_EFR);
+ if (enable)
+ efr |= UART_EFR_ECB;
+ else
+ efr &= ~UART_EFR_ECB;
+ serial_out(up, UART_EFR, efr);
+
+ /* disable 650 compatible register set, restore LCR */
+ serial_out(up, UART_LCR, lcr);
+}
+
+static void kuart_dtr_line_config(struct uart_8250_port *up, u8 dtrlc)
+{
+ u8 acr;
+
+ /* set index register to 0 to access ACR register */
+ serial_out(up, UART_SCR, UART_ACR);
+
+ /* set value register to 0x10 writing DTR mode (1,0) */
+ acr = serial_in(up, UART_LSR);
+ acr &= ~UART_ACR_DTRLC_MASK;
+ acr |= dtrlc;
+ serial_out(up, UART_LSR, acr);
+}
+
+static int kuart_rs485_config(struct uart_port *port, struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct kuart *kuart = port->private_data;
+ enum kuart_mode mode;
+ u8 dtrlc;
+
+ if (rs485->flags & SER_RS485_ENABLED) {
+ if (rs485->flags & SER_RS485_MODE_RS422)
+ mode = KUART_MODE_RS422;
+ else
+ mode = KUART_MODE_RS485;
+ } else {
+ mode = KUART_MODE_RS232;
+ }
+
+ if (mode == kuart->mode)
+ return 0;
+
+ if (kuart->flags & KUART_USE_CAPABILITY) {
+ /* deactivate physical interface, break before make */
+ kuart_set_phy_mode(kuart, KUART_MODE_NONE);
+ }
+
+ if (mode == KUART_MODE_RS485) {
+ /*
+ * Set DTR line configuration of 95x UART to DTR mode (1,0).
+ * In this mode the DTR pin drives the active-low enable pin of
+ * an external RS485 buffer. The DTR pin will be forced low
+ * whenever the transmitter is not empty, otherwise DTR pin is
+ * high.
+ */
+ dtrlc = UART_ACR_DTRLC_ENABLE_LOW;
+ } else {
+ /*
+ * Set DTR line configuration of 95x UART to DTR mode (0,0).
+ * In this mode the DTR pin is compatible with 16C450, 16C550,
+ * 16C650 and 16c670 (i.e. normal).
+ */
+ dtrlc = UART_ACR_DTRLC_COMPAT;
+ }
+
+ kuart_enhanced_mode(up, true);
+ kuart_dtr_line_config(up, dtrlc);
+ kuart_enhanced_mode(up, false);
+
+ if (kuart->flags & KUART_USE_CAPABILITY) {
+ /* activate selected physical interface */
+ kuart_set_phy_mode(kuart, mode);
+ }
+
+ kuart->mode = mode;
+
+ return 0;
+}
+
+static int kuart_probe(struct auxiliary_device *auxdev,
+ const struct auxiliary_device_id *id)
+{
+ struct device *dev = &auxdev->dev;
+ struct uart_8250_port uart = {};
+ struct resource res;
+ struct kuart *kuart;
+ int retval;
+
+ kuart = devm_kzalloc(dev, sizeof(*kuart), GFP_KERNEL);
+ if (!kuart)
+ return -ENOMEM;
+ kuart->auxdev = container_of(auxdev, struct keba_uart_auxdev, auxdev);
+ kuart->flags = id->driver_data;
+ auxiliary_set_drvdata(auxdev, kuart);
+
+ /*
+ * map only memory in front of UART registers, UART registers will be
+ * mapped by serial port
+ */
+ res = kuart->auxdev->io;
+ res.end = res.start + KUART_BASE - 1;
+ kuart->base = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(kuart->base))
+ return PTR_ERR(kuart->base);
+
+ if (kuart->flags & KUART_USE_CAPABILITY) {
+ /*
+ * supported modes are read from capability register, at least
+ * one mode other than none must be supported
+ */
+ kuart->capability = ioread8(kuart->base + KUART_CAPABILITY) &
+ KUART_CAPABILITY_MASK;
+ if ((kuart->capability & ~KUART_CAPABILITY_NONE) == 0)
+ return -EIO;
+ }
+
+ spin_lock_init(&uart.port.lock);
+ uart.port.dev = dev;
+ uart.port.mapbase = kuart->auxdev->io.start + KUART_BASE;
+ uart.port.irq = kuart->auxdev->irq;
+ uart.port.uartclk = KUART_CLK;
+ uart.port.private_data = kuart;
+
+ /* 8 bit registers are 32 bit aligned => shift register offset */
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.regshift = KUART_REGSHIFT;
+
+ /*
+ * UART mixes 16550, 16750 and 16C950 (for RS485) standard => auto
+ * configuration works best
+ */
+ uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+
+ /*
+ * UART supports RS485, RS422 and RS232 with switching of physical
+ * interface
+ */
+ uart.port.rs485_config = kuart_rs485_config;
+ if (kuart->flags & KUART_RS485) {
+ uart.port.rs485_supported.flags = SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND;
+ uart.port.rs485.flags = SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND;
+ }
+ if (kuart->flags & KUART_USE_CAPABILITY) {
+ /* default mode priority is RS485 > RS422 > RS232 */
+ if (kuart->capability & KUART_CAPABILITY_RS422) {
+ uart.port.rs485_supported.flags |= SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND |
+ SER_RS485_MODE_RS422;
+ uart.port.rs485.flags = SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND |
+ SER_RS485_MODE_RS422;
+ }
+ if (kuart->capability & KUART_CAPABILITY_RS485) {
+ uart.port.rs485_supported.flags |= SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND;
+ uart.port.rs485.flags = SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND;
+ }
+ }
+
+ retval = serial8250_register_8250_port(&uart);
+ if (retval < 0) {
+ dev_err(&auxdev->dev, "UART registration failed!\n");
+ return retval;
+ }
+ kuart->line = retval;
+
+ return 0;
+}
+
+static void kuart_remove(struct auxiliary_device *auxdev)
+{
+ struct kuart *kuart = auxiliary_get_drvdata(auxdev);
+
+ if (kuart->flags & KUART_USE_CAPABILITY)
+ kuart_set_phy_mode(kuart, KUART_MODE_NONE);
+
+ serial8250_unregister_port(kuart->line);
+}
+
+static const struct auxiliary_device_id kuart_devtype_aux[] = {
+ { .name = "keba.rs485-uart", .driver_data = KUART_RS485 },
+ { .name = "keba.rs232-uart", .driver_data = 0 },
+ { .name = "keba.uart", .driver_data = KUART_USE_CAPABILITY },
+ {}
+};
+MODULE_DEVICE_TABLE(auxiliary, kuart_devtype_aux);
+
+static struct auxiliary_driver kuart_driver_aux = {
+ .name = KUART,
+ .id_table = kuart_devtype_aux,
+ .probe = kuart_probe,
+ .remove = kuart_remove,
+};
+module_auxiliary_driver(kuart_driver_aux);
+
+MODULE_AUTHOR("Gerhard Engleder <eg@keba.com>");
+MODULE_DESCRIPTION("KEBA 8250 serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c
new file mode 100644
index 000000000000..53153a116c01
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_loongson.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Serial Port driver for Loongson family chips
+ *
+ * Copyright (C) 2020-2025 Loongson Technology Corporation Limited
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/property.h>
+#include <linux/math.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm.h>
+#include <linux/reset.h>
+
+#include "8250.h"
+
+/* Divisor Latch Fraction Register */
+#define LOONGSON_UART_DLF 0x2
+
+#define LOONGSON_QUOT_FRAC_MASK GENMASK(7, 0)
+#define LOONGSON_QUOT_DIV_MASK GENMASK(15, 8)
+
+struct loongson_uart_ddata {
+ bool has_frac;
+ u8 mcr_invert;
+ u8 msr_invert;
+};
+
+static const struct loongson_uart_ddata ls2k0500_uart_data = {
+ .has_frac = false,
+ .mcr_invert = UART_MCR_RTS | UART_MCR_DTR,
+ .msr_invert = UART_MSR_CTS | UART_MSR_DSR,
+};
+
+static const struct loongson_uart_ddata ls2k1500_uart_data = {
+ .has_frac = true,
+ .mcr_invert = UART_MCR_RTS | UART_MCR_DTR,
+ .msr_invert = 0,
+};
+
+struct loongson_uart_priv {
+ int line;
+ struct clk *clk;
+ struct resource *res;
+ struct reset_control *rst;
+ const struct loongson_uart_ddata *ddata;
+};
+
+static u8 serial_fixup(struct uart_port *p, unsigned int offset, u8 val)
+{
+ struct loongson_uart_priv *priv = p->private_data;
+
+ switch (offset) {
+ case UART_MCR:
+ return val ^ priv->ddata->mcr_invert;
+ case UART_MSR:
+ return val ^ priv->ddata->msr_invert;
+ default:
+ return val;
+ }
+}
+
+static u32 loongson_serial_in(struct uart_port *p, unsigned int offset)
+{
+ u8 val;
+
+ val = readb(p->membase + (offset << p->regshift));
+
+ return serial_fixup(p, offset, val);
+}
+
+static void loongson_serial_out(struct uart_port *p, unsigned int offset, unsigned int value)
+{
+ u8 val;
+
+ offset <<= p->regshift;
+ val = serial_fixup(p, offset, value);
+ writeb(val, p->membase + offset);
+}
+
+static unsigned int loongson_frac_get_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int *frac)
+{
+ unsigned int quot;
+
+ quot = DIV_ROUND_CLOSEST((port->uartclk << 4), baud);
+ *frac = FIELD_GET(LOONGSON_QUOT_FRAC_MASK, quot);
+
+ return FIELD_GET(LOONGSON_QUOT_DIV_MASK, quot);
+}
+
+static void loongson_frac_set_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
+ serial_dl_write(up, quot);
+ serial_port_out(port, LOONGSON_UART_DLF, quot_frac);
+}
+
+static int loongson_uart_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uart_8250_port uart = {};
+ struct loongson_uart_priv *priv;
+ struct uart_port *port;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->ddata = device_get_match_data(dev);
+
+ port = &uart.port;
+ spin_lock_init(&port->lock);
+ port->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_IOREMAP;
+ port->iotype = UPIO_MEM;
+ port->regshift = 0;
+ port->dev = dev;
+ port->type = PORT_16550A;
+ port->private_data = priv;
+
+ port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &priv->res);
+ if (!port->membase)
+ return -ENOMEM;
+
+ port->mapbase = priv->res->start;
+ port->mapsize = resource_size(priv->res);
+ port->serial_in = loongson_serial_in;
+ port->serial_out = loongson_serial_out;
+
+ if (priv->ddata->has_frac) {
+ port->get_divisor = loongson_frac_get_divisor;
+ port->set_divisor = loongson_frac_set_divisor;
+ }
+
+ ret = uart_read_port_properties(port);
+ if (ret)
+ return ret;
+
+ if (!port->uartclk) {
+ priv->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "Unable to determine clock frequency!\n");
+ port->uartclk = clk_get_rate(priv->clk);
+ }
+
+ priv->rst = devm_reset_control_get_optional_shared(dev, NULL);
+ if (IS_ERR(priv->rst))
+ return PTR_ERR(priv->rst);
+
+ ret = reset_control_deassert(priv->rst);
+ if (ret)
+ return ret;
+
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0) {
+ reset_control_assert(priv->rst);
+ return ret;
+ }
+
+ priv->line = ret;
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static void loongson_uart_remove(struct platform_device *pdev)
+{
+ struct loongson_uart_priv *priv = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(priv->line);
+ reset_control_assert(priv->rst);
+}
+
+static int loongson_uart_suspend(struct device *dev)
+{
+ struct loongson_uart_priv *priv = dev_get_drvdata(dev);
+ struct uart_8250_port *up = serial8250_get_port(priv->line);
+
+ serial8250_suspend_port(priv->line);
+
+ if (!uart_console(&up->port) || console_suspend_enabled)
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static int loongson_uart_resume(struct device *dev)
+{
+ struct loongson_uart_priv *priv = dev_get_drvdata(dev);
+ struct uart_8250_port *up = serial8250_get_port(priv->line);
+ int ret;
+
+ if (!uart_console(&up->port) || console_suspend_enabled) {
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+ }
+
+ serial8250_resume_port(priv->line);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(loongson_uart_pm_ops, loongson_uart_suspend,
+ loongson_uart_resume);
+
+static const struct of_device_id loongson_uart_of_ids[] = {
+ { .compatible = "loongson,ls2k0500-uart", .data = &ls2k0500_uart_data },
+ { .compatible = "loongson,ls2k1500-uart", .data = &ls2k1500_uart_data },
+ { },
+};
+MODULE_DEVICE_TABLE(of, loongson_uart_of_ids);
+
+static struct platform_driver loongson_uart_driver = {
+ .probe = loongson_uart_probe,
+ .remove = loongson_uart_remove,
+ .driver = {
+ .name = "loongson-uart",
+ .pm = pm_ptr(&loongson_uart_pm_ops),
+ .of_match_table = loongson_uart_of_ids,
+ },
+};
+
+module_platform_driver(loongson_uart_driver);
+
+MODULE_DESCRIPTION("Loongson UART driver");
+MODULE_AUTHOR("Loongson Technology Corporation Limited.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index d178b6c54ea1..9799356b65f7 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -95,7 +95,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
u32 spd;
int ret;
- memset(port, 0, sizeof *port);
+ memset(port, 0, sizeof(*port));
pm_runtime_enable(&ofdev->dev);
pm_runtime_get_sync(&ofdev->dev);
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 152f914c599d..c5a932f48f74 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -95,6 +95,11 @@
#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381
#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683
+#define PCI_DEVICE_ID_ADDIDATA_CPCI7500 0x7003
+#define PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG 0x7024
+#define PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG 0x7025
+#define PCI_DEVICE_ID_ADDIDATA_CPCI7300_NG 0x7026
+
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588
@@ -165,7 +170,15 @@ static int
setup_port(struct serial_private *priv, struct uart_8250_port *port,
u8 bar, unsigned int offset, int regshift)
{
- return serial8250_pci_setup_port(priv->dev, port, bar, offset, regshift);
+ void __iomem *iomem = NULL;
+
+ if (pci_resource_flags(priv->dev, bar) & IORESOURCE_MEM) {
+ iomem = pcim_iomap(priv->dev, bar, 0);
+ if (!iomem)
+ return -ENOMEM;
+ }
+
+ return serial8250_pci_setup_port(priv->dev, port, bar, offset, regshift, iomem);
}
/*
@@ -5996,6 +6009,38 @@ static const struct pci_device_id serial_pci_tbl[] = {
0,
pbn_ADDIDATA_PCIe_8_3906250 },
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_CPCI7500,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_2_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_CPCI7300_NG,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_1_115200 },
+
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
PCI_VENDOR_ID_IBM, 0x0299,
0, 0, pbn_b0_bt_2_115200 },
@@ -6178,7 +6223,6 @@ static pci_ers_result_t serial8250_io_slot_reset(struct pci_dev *dev)
return PCI_ERS_RESULT_DISCONNECT;
pci_restore_state(dev);
- pci_save_state(dev);
return PCI_ERS_RESULT_RECOVERED;
}
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
index 4c149db84692..feeede164886 100644
--- a/drivers/tty/serial/8250/8250_pci1xxxx.c
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
@@ -671,7 +671,7 @@ static int pci1xxxx_resume(struct device *dev)
}
static int pci1xxxx_setup(struct pci_dev *pdev,
- struct uart_8250_port *port, int port_idx, int rev)
+ struct uart_8250_port *port, int port_idx, struct pci1xxxx_8250 *priv)
{
int ret;
@@ -698,12 +698,12 @@ static int pci1xxxx_setup(struct pci_dev *pdev,
* C0 and later revisions support Burst operation.
* RTS workaround in mctrl is applicable only to B0.
*/
- if (rev >= 0xC0)
+ if (priv->dev_rev >= 0xC0)
port->port.handle_irq = pci1xxxx_handle_irq;
- else if (rev == 0xB0)
+ else if (priv->dev_rev == 0xB0)
port->port.set_mctrl = pci1xxxx_set_mctrl;
- ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0);
+ ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0, priv->membase);
if (ret < 0)
return ret;
@@ -821,7 +821,7 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
else
uart.port.irq = pci_irq_vector(pdev, 0);
- rc = pci1xxxx_setup(pdev, &uart, port_idx, priv->dev_rev);
+ rc = pci1xxxx_setup(pdev, &uart, port_idx, priv);
if (rc) {
dev_warn(dev, "Failed to setup port %u\n", i);
continue;
diff --git a/drivers/tty/serial/8250/8250_pcilib.c b/drivers/tty/serial/8250/8250_pcilib.c
index d8d0ae0d7238..9d5d2531a33b 100644
--- a/drivers/tty/serial/8250/8250_pcilib.c
+++ b/drivers/tty/serial/8250/8250_pcilib.c
@@ -22,19 +22,16 @@ int serial_8250_warn_need_ioport(struct pci_dev *dev)
EXPORT_SYMBOL_NS_GPL(serial_8250_warn_need_ioport, "SERIAL_8250_PCI");
int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port,
- u8 bar, unsigned int offset, int regshift)
+ u8 bar, unsigned int offset, int regshift, void __iomem *iomem)
{
if (bar >= PCI_STD_NUM_BARS)
return -EINVAL;
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
- if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
- return -ENOMEM;
-
port->port.iotype = UPIO_MEM;
port->port.iobase = 0;
port->port.mapbase = pci_resource_start(dev, bar) + offset;
- port->port.membase = pcim_iomap_table(dev)[bar] + offset;
+ port->port.membase = iomem + offset;
port->port.regshift = regshift;
} else if (IS_ENABLED(CONFIG_HAS_IOPORT)) {
port->port.iotype = UPIO_PORT;
diff --git a/drivers/tty/serial/8250/8250_pcilib.h b/drivers/tty/serial/8250/8250_pcilib.h
index 16a274574cde..ab18de8d1355 100644
--- a/drivers/tty/serial/8250/8250_pcilib.h
+++ b/drivers/tty/serial/8250/8250_pcilib.h
@@ -12,6 +12,6 @@ struct pci_dev;
struct uart_8250_port;
int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, u8 bar,
- unsigned int offset, int regshift);
+ unsigned int offset, int regshift, void __iomem *iomem);
int serial_8250_warn_need_ioport(struct pci_dev *dev);
diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c
index b27981340e76..86d12d2b5907 100644
--- a/drivers/tty/serial/8250/8250_platform.c
+++ b/drivers/tty/serial/8250/8250_platform.c
@@ -29,10 +29,8 @@
* Configuration:
* share_irqs: Whether we pass IRQF_SHARED to request_irq().
* This option is unsafe when used on edge-triggered interrupts.
- * skip_txen_test: Force skip of txen test at init time.
*/
-unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
-unsigned int skip_txen_test;
+static bool share_irqs = IS_ENABLED(CONFIG_SERIAL_8250_SHARE_IRQ);
unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
@@ -60,7 +58,7 @@ EXPORT_SYMBOL(serial8250_set_isa_configurator);
static void __init __serial8250_isa_init_ports(void)
{
- int i, irqflag = 0;
+ int i;
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
@@ -75,10 +73,7 @@ static void __init __serial8250_isa_init_ports(void)
/* chain base port ops to support Remote Supervisor Adapter */
univ8250_port_ops = *univ8250_port_base_ops;
- univ8250_rsa_support(&univ8250_port_ops);
-
- if (share_irqs)
- irqflag = IRQF_SHARED;
+ univ8250_rsa_support(&univ8250_port_ops, univ8250_port_base_ops);
for (i = 0; i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; i++) {
struct uart_8250_port *up = serial8250_get_port(i);
@@ -94,7 +89,9 @@ static void __init __serial8250_isa_init_ports(void)
port->iotype = old_serial_port[i].io_type;
port->regshift = old_serial_port[i].iomem_reg_shift;
- port->irqflags |= irqflag;
+ if (share_irqs)
+ port->irqflags |= IRQF_SHARED;
+
if (serial8250_isa_config != NULL)
serial8250_isa_config(i, &up->port, &up->capabilities);
}
@@ -157,15 +154,12 @@ static int serial8250_probe_acpi(struct platform_device *pdev)
static int serial8250_probe_platform(struct platform_device *dev, struct plat_serial8250_port *p)
{
- int ret, i, irqflag = 0;
+ int ret, i;
struct uart_8250_port *uart __free(kfree) = kzalloc(sizeof(*uart), GFP_KERNEL);
if (!uart)
return -ENOMEM;
- if (share_irqs)
- irqflag = IRQF_SHARED;
-
for (i = 0; p && p->flags != 0; p++, i++) {
uart->port.iobase = p->iobase;
uart->port.membase = p->membase;
@@ -193,7 +187,10 @@ static int serial8250_probe_platform(struct platform_device *dev, struct plat_se
uart->port.get_mctrl = p->get_mctrl;
uart->port.pm = p->pm;
uart->port.dev = &dev->dev;
- uart->port.irqflags |= irqflag;
+
+ if (share_irqs)
+ uart->port.irqflags |= IRQF_SHARED;
+
ret = serial8250_register_8250_port(uart);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
@@ -380,40 +377,10 @@ module_exit(serial8250_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 serial platform driver");
-module_param_hw(share_irqs, uint, other, 0644);
+module_param_hw(share_irqs, bool, other, 0644);
MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)");
module_param(nr_uarts, uint, 0644);
MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
-module_param(skip_txen_test, uint, 0644);
-MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
-
MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
-
-#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
-#ifndef MODULE
-/*
- * This module was renamed to 8250_core in 3.7. Keep the old "8250" name
- * working as well for the module options so we don't break people. We
- * need to keep the names identical and the convenient macros will happily
- * refuse to let us do that by failing the build with redefinition errors
- * of global variables. So we stick them inside a dummy function to avoid
- * those conflicts. The options still get parsed, and the redefined
- * MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
- *
- * This is hacky. I'm sorry.
- */
-static void __used s8250_options(void)
-{
-#undef MODULE_PARAM_PREFIX
-#define MODULE_PARAM_PREFIX "8250_core."
-
- module_param_cb(share_irqs, &param_ops_uint, &share_irqs, 0644);
- module_param_cb(nr_uarts, &param_ops_uint, &nr_uarts, 0644);
- module_param_cb(skip_txen_test, &param_ops_uint, &skip_txen_test, 0644);
-}
-#else
-MODULE_ALIAS("8250_core");
-#endif
-#endif
diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c
index 40a3dbd9e452..fff9395948e3 100644
--- a/drivers/tty/serial/8250/8250_rsa.c
+++ b/drivers/tty/serial/8250/8250_rsa.c
@@ -14,6 +14,8 @@
static unsigned long probe_rsa[PORT_RSA_MAX];
static unsigned int probe_rsa_count;
+static const struct uart_ops *core_port_base_ops;
+
static int rsa8250_request_resource(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
@@ -67,7 +69,7 @@ static void univ8250_config_port(struct uart_port *port, int flags)
}
}
- univ8250_port_base_ops->config_port(port, flags);
+ core_port_base_ops->config_port(port, flags);
if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA)
rsa8250_release_resource(up);
@@ -78,11 +80,11 @@ static int univ8250_request_port(struct uart_port *port)
struct uart_8250_port *up = up_to_u8250p(port);
int ret;
- ret = univ8250_port_base_ops->request_port(port);
+ ret = core_port_base_ops->request_port(port);
if (ret == 0 && port->type == PORT_RSA) {
ret = rsa8250_request_resource(up);
if (ret < 0)
- univ8250_port_base_ops->release_port(port);
+ core_port_base_ops->release_port(port);
}
return ret;
@@ -94,15 +96,25 @@ static void univ8250_release_port(struct uart_port *port)
if (port->type == PORT_RSA)
rsa8250_release_resource(up);
- univ8250_port_base_ops->release_port(port);
+ core_port_base_ops->release_port(port);
}
-void univ8250_rsa_support(struct uart_ops *ops)
+/*
+ * It is not allowed to directly reference any symbols from 8250.ko here as
+ * that would result in a dependency loop between the 8250.ko and
+ * 8250_base.ko modules. This function is called from 8250.ko and is used to
+ * break the symbolic dependency cycle. Anything that is needed from 8250.ko
+ * has to be passed as pointers to this function which then can adjust those
+ * variables on 8250.ko side or store them locally as needed.
+ */
+void univ8250_rsa_support(struct uart_ops *ops, const struct uart_ops *core_ops)
{
+ core_port_base_ops = core_ops;
ops->config_port = univ8250_config_port;
ops->request_port = univ8250_request_port;
ops->release_port = univ8250_release_port;
}
+EXPORT_SYMBOL_FOR_MODULES(univ8250_rsa_support, "8250");
module_param_hw_array(probe_rsa, ulong, ioport, &probe_rsa_count, 0444);
MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
@@ -146,7 +158,6 @@ void rsa_enable(struct uart_8250_port *up)
if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
serial_out(up, UART_RSA_FRR, 0);
}
-EXPORT_SYMBOL_FOR_MODULES(rsa_enable, "8250_base");
/*
* Attempts to turn off the RSA FIFO and resets the RSA board back to 115kbps compat mode. It is
@@ -178,7 +189,6 @@ void rsa_disable(struct uart_8250_port *up)
if (result)
up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
}
-EXPORT_SYMBOL_FOR_MODULES(rsa_disable, "8250_base");
void rsa_autoconfig(struct uart_8250_port *up)
{
@@ -191,7 +201,6 @@ void rsa_autoconfig(struct uart_8250_port *up)
if (__rsa_enable(up))
up->port.type = PORT_RSA;
}
-EXPORT_SYMBOL_FOR_MODULES(rsa_autoconfig, "8250_base");
void rsa_reset(struct uart_8250_port *up)
{
@@ -200,28 +209,3 @@ void rsa_reset(struct uart_8250_port *up)
serial_out(up, UART_RSA_FRR, 0);
}
-EXPORT_SYMBOL_FOR_MODULES(rsa_reset, "8250_base");
-
-#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
-#ifndef MODULE
-/*
- * Keep the old "8250" name working as well for the module options so we don't
- * break people. We need to keep the names identical and the convenient macros
- * will happily refuse to let us do that by failing the build with redefinition
- * errors of global variables. So we stick them inside a dummy function to
- * avoid those conflicts. The options still get parsed, and the redefined
- * MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
- *
- * This is hacky. I'm sorry.
- */
-static void __used rsa8250_options(void)
-{
-#undef MODULE_PARAM_PREFIX
-#define MODULE_PARAM_PREFIX "8250_core."
-
- __module_param_call(MODULE_PARAM_PREFIX, probe_rsa,
- &param_array_ops, .arr = &__param_arr_probe_rsa,
- 0444, -1, 0);
-}
-#endif
-#endif
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index f64ef0819cd4..c488ff6f2865 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -34,23 +34,6 @@ config SERIAL_8250
Most people will say Y or M here, so that they can use serial mice,
modems and similar devices connecting to the standard serial ports.
-config SERIAL_8250_DEPRECATED_OPTIONS
- bool "Support 8250_core.* kernel options (DEPRECATED)"
- depends on SERIAL_8250
- default y
- help
- In 3.7 we renamed 8250 to 8250_core by mistake, so now we have to
- accept kernel parameters in both forms like 8250_core.nr_uarts=4 and
- 8250.nr_uarts=4. We now renamed the module back to 8250, but if
- anybody noticed in 3.7 and changed their userspace we still have to
- keep the 8250_core.* options around until they revert the changes
- they already did.
-
- If 8250 is built as a module, this adds 8250_core alias instead.
-
- If you did not notice yet and/or you have userspace from pre-3.7, it
- is safe (and recommended) to say N here.
-
config SERIAL_8250_PNP
bool "8250/16550 PNP device support" if EXPERT
depends on SERIAL_8250 && PNP
@@ -430,6 +413,19 @@ config SERIAL_8250_IOC3
behind the IOC3 device on those systems. Maximum baud speed is
38400bps using this driver.
+config SERIAL_8250_KEBA
+ tristate "Support for KEBA 8250 UART"
+ depends on SERIAL_8250
+ depends on KEBA_CP500
+ help
+ Selecting this option will add support for KEBA UARTs. These UARTs
+ are used for the serial interfaces of KEBA PLCs.
+
+ This driver can also be built as a module. If so, the module will
+ be called 8250_keba.
+
+ If unsure, say N.
+
config SERIAL_8250_RT288X
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
depends on SERIAL_8250
@@ -468,6 +464,16 @@ config SERIAL_8250_OMAP_TTYO_FIXUP
not booting kernel because the serial console remains silent in case
they forgot to update the command line.
+config SERIAL_8250_LOONGSON
+ tristate "Loongson 8250 based serial port"
+ depends on SERIAL_8250
+ depends on LOONGARCH || COMPILE_TEST
+ help
+ If you have a machine based on LoongArch CPU you can enable
+ its onboard serial ports by enabling this option. The option
+ is applicable to both devicetree and ACPI, say Y to this option.
+ If unsure, say N.
+
config SERIAL_8250_LPC18XX
tristate "NXP LPC18xx/43xx serial port support"
depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 513a0941c284..6d21402b4435 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -7,7 +7,6 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o
8250-y := 8250_core.o
8250-y += 8250_platform.o
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
-8250-$(CONFIG_SERIAL_8250_RSA) += 8250_rsa.o
obj-$(CONFIG_SERIAL_8250) += 8250_base.o
8250_base-y := 8250_port.o
@@ -15,6 +14,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250_base.o
8250_base-$(CONFIG_SERIAL_8250_DWLIB) += 8250_dwlib.o
8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
8250_base-$(CONFIG_SERIAL_8250_PCILIB) += 8250_pcilib.o
+8250_base-$(CONFIG_SERIAL_8250_RSA) += 8250_rsa.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
@@ -38,6 +38,8 @@ obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o
+obj-$(CONFIG_SERIAL_8250_KEBA) += 8250_keba.o
+obj-$(CONFIG_SERIAL_8250_LOONGSON) += 8250_loongson.o
obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 282116765e64..59221cce0028 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1044,7 +1044,7 @@ config SERIAL_SCCNXP_CONSOLE
config SERIAL_SC16IS7XX
tristate "NXP SC16IS7xx UART support"
- depends on SPI_MASTER || I2C
+ depends on SPI_MASTER || I2C || COMPILE_TEST
select SERIAL_CORE
select SERIAL_SC16IS7XX_SPI if SPI_MASTER
select SERIAL_SC16IS7XX_I2C if I2C
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 22939841b1de..7f17d288c807 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -628,7 +628,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
dmatx->len = count;
dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count,
DMA_TO_DEVICE);
- if (dmatx->dma == DMA_MAPPING_ERROR) {
+ if (dma_mapping_error(dma_dev->dev, dmatx->dma)) {
uap->dmatx.queued = false;
dev_dbg(uap->port.dev, "unable to map TX DMA\n");
return -EBUSY;
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index 8bb33556b312..5b491db9d2fc 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -560,6 +560,64 @@ static int ar933x_uart_verify_port(struct uart_port *port,
return 0;
}
+#ifdef CONFIG_CONSOLE_POLL
+static int ar933x_poll_get_char(struct uart_port *port)
+{
+ struct ar933x_uart_port *up =
+ container_of(port, struct ar933x_uart_port, port);
+ unsigned int rdata;
+ unsigned char ch;
+ u32 imr;
+
+ /* Disable all interrupts */
+ imr = ar933x_uart_read(up, AR933X_UART_INT_EN_REG);
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0);
+
+ rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG);
+ if ((rdata & AR933X_UART_DATA_RX_CSR) == 0) {
+ /* Enable interrupts */
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, imr);
+ return NO_POLL_CHAR;
+ }
+
+ /* remove the character from the FIFO */
+ ar933x_uart_write(up, AR933X_UART_DATA_REG,
+ AR933X_UART_DATA_RX_CSR);
+
+ ch = rdata & AR933X_UART_DATA_TX_RX_MASK;
+
+ /* Enable interrupts */
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, imr);
+
+ return ch;
+}
+
+static void ar933x_poll_put_char(struct uart_port *port, unsigned char c)
+{
+ struct ar933x_uart_port *up =
+ container_of(port, struct ar933x_uart_port, port);
+ u32 imr;
+
+ /* Disable all interrupts */
+ imr = ar933x_uart_read(up, AR933X_UART_INT_EN_REG);
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0);
+
+ /* Wait until FIFO is empty */
+ while (!(ar933x_uart_read(up, AR933X_UART_DATA_REG) & AR933X_UART_DATA_TX_CSR))
+ cpu_relax();
+
+ /* Write a character */
+ ar933x_uart_putc(up, c);
+
+ /* Wait until FIFO is empty */
+ while (!(ar933x_uart_read(up, AR933X_UART_DATA_REG) & AR933X_UART_DATA_TX_CSR))
+ cpu_relax();
+
+ /* Enable interrupts */
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, imr);
+}
+#endif
+
static const struct uart_ops ar933x_uart_ops = {
.tx_empty = ar933x_uart_tx_empty,
.set_mctrl = ar933x_uart_set_mctrl,
@@ -576,6 +634,10 @@ static const struct uart_ops ar933x_uart_ops = {
.request_port = ar933x_uart_request_port,
.config_port = ar933x_uart_config_port,
.verify_port = ar933x_uart_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = ar933x_poll_get_char,
+ .poll_put_char = ar933x_poll_put_char,
+#endif
};
static int ar933x_config_rs485(struct uart_port *port, struct ktermios *termios,
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index c9519e649e82..1bd7ec9c81ea 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -3087,6 +3087,8 @@ static int lpuart_suspend_noirq(struct device *dev)
static int lpuart_resume_noirq(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
+ struct tty_port *port = &sport->port.state->port;
+ bool wake_active;
u32 stat;
pinctrl_pm_select_default_state(dev);
@@ -3098,6 +3100,12 @@ static int lpuart_resume_noirq(struct device *dev)
if (lpuart_is_32(sport)) {
stat = lpuart32_read(&sport->port, UARTSTAT);
lpuart32_write(&sport->port, stat, UARTSTAT);
+
+ /* check whether lpuart wakeup was triggered */
+ wake_active = stat & (UARTSTAT_RDRF | UARTSTAT_RXEDGIF);
+
+ if (wake_active && irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)))
+ pm_wakeup_event(tty_port_tty_get(port)->dev, 0);
}
}
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 7fb995a8490e..b7e33a896589 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -760,7 +760,7 @@ static void load_code(struct icom_port *icom_port)
dma_free_coherent(&dev->dev, 4096, new_page, temp_pci);
}
-static int startup(struct icom_port *icom_port)
+static int icom_startup(struct icom_port *icom_port)
{
unsigned long temp;
unsigned char cable_id, raw_cable_id;
@@ -832,7 +832,7 @@ unlock:
return 0;
}
-static void shutdown(struct icom_port *icom_port)
+static void icom_shutdown(struct icom_port *icom_port)
{
unsigned long temp;
unsigned char cmdReg;
@@ -1311,7 +1311,7 @@ static int icom_open(struct uart_port *port)
int retval;
kref_get(&icom_port->adapter->kref);
- retval = startup(icom_port);
+ retval = icom_startup(icom_port);
if (retval) {
kref_put(&icom_port->adapter->kref, icom_kref_release);
@@ -1333,7 +1333,7 @@ static void icom_close(struct uart_port *port)
cmdReg = readb(&icom_port->dram->CmdReg);
writeb(cmdReg & ~CMD_RCV_ENABLE, &icom_port->dram->CmdReg);
- shutdown(icom_port);
+ icom_shutdown(icom_port);
kref_put(&icom_port->adapter->kref, icom_kref_release);
}
@@ -1723,6 +1723,7 @@ static int icom_probe(struct pci_dev *dev,
retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg);
if (retval) {
dev_err(&dev->dev, "PCI Config read FAILED\n");
+ retval = pcibios_err_to_errno(retval);
goto probe_exit0;
}
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 500dfc009d03..c488e5d372ff 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -30,7 +30,7 @@
#include <linux/iopoll.h>
#include <linux/dma-mapping.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
#include <linux/dma/imx-dma.h>
#include "serial_mctrl_gpio.h"
@@ -2697,16 +2697,32 @@ static void imx_uart_save_context(struct imx_port *sport)
/* called with irq off */
static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
{
- u32 ucr3;
+ struct tty_port *port = &sport->port.state->port;
+ struct device *tty_dev;
+ bool may_wake = false, wake_active = false;
+ u32 ucr3, usr1;
+
+ scoped_guard(tty_port_tty, port) {
+ struct tty_struct *tty = scoped_tty();
+
+ tty_dev = tty->dev;
+ may_wake = tty_dev && device_may_wakeup(tty_dev);
+ }
+
+ /* only configure the wake register when device set as wakeup source */
+ if (!may_wake)
+ return;
uart_port_lock_irq(&sport->port);
+ usr1 = imx_uart_readl(sport, USR1);
ucr3 = imx_uart_readl(sport, UCR3);
if (on) {
imx_uart_writel(sport, USR1_AWAKE, USR1);
ucr3 |= UCR3_AWAKEN;
} else {
ucr3 &= ~UCR3_AWAKEN;
+ wake_active = usr1 & USR1_AWAKE;
}
imx_uart_writel(sport, ucr3, UCR3);
@@ -2717,10 +2733,14 @@ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
ucr1 |= UCR1_RTSDEN;
} else {
ucr1 &= ~UCR1_RTSDEN;
+ wake_active = wake_active || (usr1 & USR1_RTSD);
}
imx_uart_writel(sport, ucr1, UCR1);
}
+ if (wake_active && irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)))
+ pm_wakeup_event(tty_port_tty_get(port)->dev, 0);
+
uart_port_unlock_irq(&sport->port);
}
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
index 417a5b6bffc3..8d21373cae57 100644
--- a/drivers/tty/serial/jsm/jsm_driver.c
+++ b/drivers/tty/serial/jsm/jsm_driver.c
@@ -355,7 +355,6 @@ static void jsm_io_resume(struct pci_dev *pdev)
struct jsm_board *brd = pci_get_drvdata(pdev);
pci_restore_state(pdev);
- pci_save_state(pdev);
jsm_uart_port_init(brd);
}
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 85f6c5a76e0f..5a955c80a853 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -577,7 +577,6 @@ static int __init kgdboc_earlycon_init(char *opt)
console_list_lock();
for_each_console(con) {
if (con->write && con->read &&
- (con->flags & (CON_BOOT | CON_ENABLED)) &&
(!opt || !opt[0] || strcmp(con->name, opt) == 0))
break;
}
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
index b417faead20f..3a77a7e5c7bc 100644
--- a/drivers/tty/serial/mux.c
+++ b/drivers/tty/serial/mux.c
@@ -343,7 +343,7 @@ static int mux_verify_port(struct uart_port *port, struct serial_struct *ser)
}
/**
- * mux_drv_poll - Mux poll function.
+ * mux_poll - Mux poll function.
* @unused: Unused variable
*
* This function periodically polls the Serial MUX to check for new data.
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 8058b839b26c..6ce6528f5c10 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -14,6 +14,7 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -101,10 +102,16 @@
#define DMA_RX_BUF_SIZE 2048
static DEFINE_IDA(port_ida);
+#define DOMAIN_IDX_POWER 0
+#define DOMAIN_IDX_PERF 1
struct qcom_geni_device_data {
bool console;
enum geni_se_xfer_mode mode;
+ struct dev_pm_domain_attach_data pd_data;
+ int (*resources_init)(struct uart_port *uport);
+ int (*set_rate)(struct uart_port *uport, unsigned int baud);
+ int (*power_state)(struct uart_port *uport, bool state);
};
struct qcom_geni_private_data {
@@ -142,6 +149,7 @@ struct qcom_geni_serial_port {
struct qcom_geni_private_data private_data;
const struct qcom_geni_device_data *dev_data;
+ struct dev_pm_domain_list *pd_list;
};
static const struct uart_ops qcom_geni_console_pops;
@@ -1299,6 +1307,42 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
return 0;
}
+static int geni_serial_set_level(struct uart_port *uport, unsigned int baud)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ struct device *perf_dev = port->pd_list->pd_devs[DOMAIN_IDX_PERF];
+
+ /*
+ * The performance protocol sets UART communication
+ * speeds by selecting different performance levels
+ * through the OPP framework.
+ *
+ * Supported perf levels for baudrates in firmware are below
+ * +---------------------+--------------------+
+ * | Perf level value | Baudrate values |
+ * +---------------------+--------------------+
+ * | 300 | 300 |
+ * | 1200 | 1200 |
+ * | 2400 | 2400 |
+ * | 4800 | 4800 |
+ * | 9600 | 9600 |
+ * | 19200 | 19200 |
+ * | 38400 | 38400 |
+ * | 57600 | 57600 |
+ * | 115200 | 115200 |
+ * | 230400 | 230400 |
+ * | 460800 | 460800 |
+ * | 921600 | 921600 |
+ * | 2000000 | 2000000 |
+ * | 3000000 | 3000000 |
+ * | 3200000 | 3200000 |
+ * | 4000000 | 4000000 |
+ * +---------------------+--------------------+
+ */
+
+ return dev_pm_opp_set_level(perf_dev, baud);
+}
+
static void qcom_geni_serial_set_termios(struct uart_port *uport,
struct ktermios *termios,
const struct ktermios *old)
@@ -1317,7 +1361,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
/* baud rate */
baud = uart_get_baud_rate(uport, termios, old, 300, 8000000);
- ret = geni_serial_set_rate(uport, baud);
+ ret = port->dev_data->set_rate(uport, baud);
if (ret)
return;
@@ -1604,8 +1648,27 @@ static int geni_serial_resources_off(struct uart_port *uport)
return 0;
}
-static int geni_serial_resource_init(struct qcom_geni_serial_port *port)
+static int geni_serial_resource_state(struct uart_port *uport, bool power_on)
+{
+ return power_on ? geni_serial_resources_on(uport) : geni_serial_resources_off(uport);
+}
+
+static int geni_serial_pwr_init(struct uart_port *uport)
{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ int ret;
+
+ ret = dev_pm_domain_attach_list(port->se.dev,
+ &port->dev_data->pd_data, &port->pd_list);
+ if (ret <= 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int geni_serial_resource_init(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
int ret;
port->se.clk = devm_clk_get(port->se.dev, "se");
@@ -1650,10 +1713,10 @@ static void qcom_geni_serial_pm(struct uart_port *uport,
old_state = UART_PM_STATE_OFF;
if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
- geni_serial_resources_on(uport);
+ pm_runtime_resume_and_get(uport->dev);
else if (new_state == UART_PM_STATE_OFF &&
old_state == UART_PM_STATE_ON)
- geni_serial_resources_off(uport);
+ pm_runtime_put_sync(uport->dev);
}
@@ -1756,13 +1819,16 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
port->se.dev = &pdev->dev;
port->se.wrapper = dev_get_drvdata(pdev->dev.parent);
- ret = geni_serial_resource_init(port);
+ ret = port->dev_data->resources_init(uport);
if (ret)
return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
+ if (!res) {
+ ret = -EINVAL;
+ goto error;
+ }
+
uport->mapbase = res->start;
uport->rs485_config = qcom_geni_rs485_config;
@@ -1774,19 +1840,26 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (!data->console) {
port->rx_buf = devm_kzalloc(uport->dev,
DMA_RX_BUF_SIZE, GFP_KERNEL);
- if (!port->rx_buf)
- return -ENOMEM;
+ if (!port->rx_buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
}
port->name = devm_kasprintf(uport->dev, GFP_KERNEL,
"qcom_geni_serial_%s%d",
uart_console(uport) ? "console" : "uart", uport->line);
- if (!port->name)
- return -ENOMEM;
+ if (!port->name) {
+ ret = -ENOMEM;
+ goto error;
+ }
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ if (irq < 0) {
+ ret = irq;
+ goto error;
+ }
+
uport->irq = irq;
uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE);
@@ -1808,16 +1881,18 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
IRQF_TRIGGER_HIGH, port->name, uport);
if (ret) {
dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
- return ret;
+ goto error;
}
ret = uart_get_rs485_mode(uport);
if (ret)
- return ret;
+ goto error;
+
+ devm_pm_runtime_enable(port->se.dev);
ret = uart_add_one_port(drv, uport);
if (ret)
- return ret;
+ goto error;
if (port->wakeup_irq > 0) {
device_init_wakeup(&pdev->dev, true);
@@ -1827,11 +1902,15 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, false);
ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, uport);
- return ret;
+ goto error;
}
}
return 0;
+
+error:
+ dev_pm_domain_detach_list(port->pd_list);
+ return ret;
}
static void qcom_geni_serial_remove(struct platform_device *pdev)
@@ -1844,6 +1923,31 @@ static void qcom_geni_serial_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, false);
ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, &port->uport);
+ dev_pm_domain_detach_list(port->pd_list);
+}
+
+static int __maybe_unused qcom_geni_serial_runtime_suspend(struct device *dev)
+{
+ struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
+ struct uart_port *uport = &port->uport;
+ int ret = 0;
+
+ if (port->dev_data->power_state)
+ ret = port->dev_data->power_state(uport, false);
+
+ return ret;
+}
+
+static int __maybe_unused qcom_geni_serial_runtime_resume(struct device *dev)
+{
+ struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
+ struct uart_port *uport = &port->uport;
+ int ret = 0;
+
+ if (port->dev_data->power_state)
+ ret = port->dev_data->power_state(uport, true);
+
+ return ret;
}
static int qcom_geni_serial_suspend(struct device *dev)
@@ -1881,14 +1985,46 @@ static int qcom_geni_serial_resume(struct device *dev)
static const struct qcom_geni_device_data qcom_geni_console_data = {
.console = true,
.mode = GENI_SE_FIFO,
+ .resources_init = geni_serial_resource_init,
+ .set_rate = geni_serial_set_rate,
+ .power_state = geni_serial_resource_state,
};
static const struct qcom_geni_device_data qcom_geni_uart_data = {
.console = false,
.mode = GENI_SE_DMA,
+ .resources_init = geni_serial_resource_init,
+ .set_rate = geni_serial_set_rate,
+ .power_state = geni_serial_resource_state,
+};
+
+static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = {
+ .console = true,
+ .mode = GENI_SE_FIFO,
+ .pd_data = {
+ .pd_flags = PD_FLAG_DEV_LINK_ON,
+ .pd_names = (const char*[]) { "power", "perf" },
+ .num_pd_names = 2,
+ },
+ .resources_init = geni_serial_pwr_init,
+ .set_rate = geni_serial_set_level,
+};
+
+static const struct qcom_geni_device_data sa8255p_qcom_geni_uart_data = {
+ .console = false,
+ .mode = GENI_SE_DMA,
+ .pd_data = {
+ .pd_flags = PD_FLAG_DEV_LINK_ON,
+ .pd_names = (const char*[]) { "power", "perf" },
+ .num_pd_names = 2,
+ },
+ .resources_init = geni_serial_pwr_init,
+ .set_rate = geni_serial_set_level,
};
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
+ SET_RUNTIME_PM_OPS(qcom_geni_serial_runtime_suspend,
+ qcom_geni_serial_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_suspend, qcom_geni_serial_resume)
};
@@ -1898,9 +2034,17 @@ static const struct of_device_id qcom_geni_serial_match_table[] = {
.data = &qcom_geni_console_data,
},
{
+ .compatible = "qcom,sa8255p-geni-debug-uart",
+ .data = &sa8255p_qcom_geni_console_data,
+ },
+ {
.compatible = "qcom,geni-uart",
.data = &qcom_geni_uart_data,
},
+ {
+ .compatible = "qcom,sa8255p-geni-uart",
+ .data = &sa8255p_qcom_geni_uart_data,
+ },
{}
};
MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table);
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 2fb58c626daf..c1fabad6ba1f 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -2830,6 +2830,8 @@ OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
s5pv210_early_console_setup);
OF_EARLYCON_DECLARE(artpec8, "axis,artpec8-uart",
s5pv210_early_console_setup);
+OF_EARLYCON_DECLARE(exynos850, "samsung,exynos850-uart",
+ s5pv210_early_console_setup);
static int __init gs101_early_console_setup(struct earlycon_device *device,
const char *opt)
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index c7435595dce1..1fd64a47341d 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -11,6 +11,7 @@
#define DEFAULT_SYMBOL_NAMESPACE "SERIAL_NXP_SC16IS7XX"
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -49,18 +50,10 @@
#define SC16IS7XX_SPR_REG (0x07) /* Scratch Pad */
#define SC16IS7XX_TXLVL_REG (0x08) /* TX FIFO level */
#define SC16IS7XX_RXLVL_REG (0x09) /* RX FIFO level */
-#define SC16IS7XX_IODIR_REG (0x0a) /* I/O Direction
- * - only on 75x/76x
- */
-#define SC16IS7XX_IOSTATE_REG (0x0b) /* I/O State
- * - only on 75x/76x
- */
-#define SC16IS7XX_IOINTENA_REG (0x0c) /* I/O Interrupt Enable
- * - only on 75x/76x
- */
-#define SC16IS7XX_IOCONTROL_REG (0x0e) /* I/O Control
- * - only on 75x/76x
- */
+#define SC16IS7XX_IODIR_REG (0x0a) /* I/O Direction - only on 75x/76x */
+#define SC16IS7XX_IOSTATE_REG (0x0b) /* I/O State - only on 75x/76x */
+#define SC16IS7XX_IOINTENA_REG (0x0c) /* I/O Interrupt Enable - only on 75x/76x */
+#define SC16IS7XX_IOCONTROL_REG (0x0e) /* I/O Control - only on 75x/76x */
#define SC16IS7XX_EFCR_REG (0x0f) /* Extra Features Control */
/* TCR/TLR Register set: Only if ((MCR[2] == 1) && (EFR[4] == 1)) */
@@ -80,12 +73,9 @@
/* IER register bits */
#define SC16IS7XX_IER_RDI_BIT BIT(0) /* Enable RX data interrupt */
-#define SC16IS7XX_IER_THRI_BIT BIT(1) /* Enable TX holding register
- * interrupt */
-#define SC16IS7XX_IER_RLSI_BIT BIT(2) /* Enable RX line status
- * interrupt */
-#define SC16IS7XX_IER_MSI_BIT BIT(3) /* Enable Modem status
- * interrupt */
+#define SC16IS7XX_IER_THRI_BIT BIT(1) /* Enable TX holding register interrupt */
+#define SC16IS7XX_IER_RLSI_BIT BIT(2) /* Enable RX line status interrupt */
+#define SC16IS7XX_IER_MSI_BIT BIT(3) /* Enable Modem status interrupt */
/* IER register bits - write only if (EFR[4] == 1) */
#define SC16IS7XX_IER_SLEEP_BIT BIT(4) /* Enable Sleep mode */
@@ -118,9 +108,8 @@
* - only on 75x/76x
*/
#define SC16IS7XX_IIR_XOFFI_SRC 0x10 /* Received Xoff */
-#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state
- * from active (LOW)
- * to inactive (HIGH)
+#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state from active
+ * (LOW) to inactive (HIGH)
*/
/* LCR register bits */
#define SC16IS7XX_LCR_LENGTH0_BIT BIT(0) /* Word length bit 0 */
@@ -136,8 +125,7 @@
*
* STOP length bit table:
* 0 -> 1 stop bit
- * 1 -> 1-1.5 stop bits if
- * word length is 5,
+ * 1 -> 1-1.5 stop bits if word length is 5,
* 2 stop bits otherwise
*/
#define SC16IS7XX_LCR_PARITY_BIT BIT(3) /* Parity bit enable */
@@ -149,29 +137,22 @@
#define SC16IS7XX_LCR_WORD_LEN_6 (0x01)
#define SC16IS7XX_LCR_WORD_LEN_7 (0x02)
#define SC16IS7XX_LCR_WORD_LEN_8 (0x03)
-#define SC16IS7XX_LCR_CONF_MODE_A SC16IS7XX_LCR_DLAB_BIT /* Special
- * reg set */
-#define SC16IS7XX_LCR_CONF_MODE_B 0xBF /* Enhanced
- * reg set */
+#define SC16IS7XX_LCR_REG_SET_SPECIAL SC16IS7XX_LCR_DLAB_BIT /* Special reg set */
+#define SC16IS7XX_LCR_REG_SET_ENHANCED 0xBF /* Enhanced reg set */
/* MCR register bits */
-#define SC16IS7XX_MCR_DTR_BIT BIT(0) /* DTR complement
- * - only on 75x/76x
- */
+#define SC16IS7XX_MCR_DTR_BIT BIT(0) /* DTR complement - only on 75x/76x */
#define SC16IS7XX_MCR_RTS_BIT BIT(1) /* RTS complement */
-#define SC16IS7XX_MCR_TCRTLR_BIT BIT(2) /* TCR/TLR register enable */
+#define SC16IS7XX_MCR_TCRTLR_BIT BIT(2) /* TCR/TLR registers enable */
#define SC16IS7XX_MCR_LOOP_BIT BIT(4) /* Enable loopback test mode */
#define SC16IS7XX_MCR_XONANY_BIT BIT(5) /* Enable Xon Any
- * - write enabled
- * if (EFR[4] == 1)
+ * - write enabled if (EFR[4] == 1)
*/
#define SC16IS7XX_MCR_IRDA_BIT BIT(6) /* Enable IrDA mode
- * - write enabled
- * if (EFR[4] == 1)
+ * - write enabled if (EFR[4] == 1)
*/
#define SC16IS7XX_MCR_CLKSEL_BIT BIT(7) /* Divide clock by 4
- * - write enabled
- * if (EFR[4] == 1)
+ * - write enabled if (EFR[4] == 1)
*/
/* LSR register bits */
@@ -192,28 +173,19 @@
/* MSR register bits */
#define SC16IS7XX_MSR_DCTS_BIT BIT(0) /* Delta CTS Clear To Send */
-#define SC16IS7XX_MSR_DDSR_BIT BIT(1) /* Delta DSR Data Set Ready
- * or (IO4)
+#define SC16IS7XX_MSR_DDSR_BIT BIT(1) /* Delta DSR Data Set Ready or (IO4)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_DRI_BIT BIT(2) /* Delta RI Ring Indicator
- * or (IO7)
+#define SC16IS7XX_MSR_DRI_BIT BIT(2) /* Delta RI Ring Indicator or (IO7)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_DCD_BIT BIT(3) /* Delta CD Carrier Detect
- * or (IO6)
+#define SC16IS7XX_MSR_DCD_BIT BIT(3) /* Delta CD Carrier Detect or (IO6)
* - only on 75x/76x
*/
#define SC16IS7XX_MSR_CTS_BIT BIT(4) /* CTS */
-#define SC16IS7XX_MSR_DSR_BIT BIT(5) /* DSR (IO4)
- * - only on 75x/76x
- */
-#define SC16IS7XX_MSR_RI_BIT BIT(6) /* RI (IO7)
- * - only on 75x/76x
- */
-#define SC16IS7XX_MSR_CD_BIT BIT(7) /* CD (IO6)
- * - only on 75x/76x
- */
+#define SC16IS7XX_MSR_DSR_BIT BIT(5) /* DSR (IO4) - only on 75x/76x */
+#define SC16IS7XX_MSR_RI_BIT BIT(6) /* RI (IO7) - only on 75x/76x */
+#define SC16IS7XX_MSR_CD_BIT BIT(7) /* CD (IO6) - only on 75x/76x */
/*
* TCR register bits
@@ -252,54 +224,42 @@
#define SC16IS7XX_IOCONTROL_SRESET_BIT BIT(3) /* Software Reset */
/* EFCR register bits */
-#define SC16IS7XX_EFCR_9BIT_MODE_BIT BIT(0) /* Enable 9-bit or Multidrop
- * mode (RS485) */
+#define SC16IS7XX_EFCR_9BIT_MODE_BIT BIT(0) /* Enable 9-bit or Multidrop mode (RS485) */
#define SC16IS7XX_EFCR_RXDISABLE_BIT BIT(1) /* Disable receiver */
#define SC16IS7XX_EFCR_TXDISABLE_BIT BIT(2) /* Disable transmitter */
#define SC16IS7XX_EFCR_AUTO_RS485_BIT BIT(4) /* Auto RS485 RTS direction */
#define SC16IS7XX_EFCR_RTS_INVERT_BIT BIT(5) /* RTS output inversion */
#define SC16IS7XX_EFCR_IRDA_MODE_BIT BIT(7) /* IrDA mode
- * 0 = rate upto 115.2 kbit/s
- * - Only 75x/76x
- * 1 = rate upto 1.152 Mbit/s
- * - Only 76x
+ * 0 = rate up to 115.2 kbit/s - Only 75x/76x
+ * 1 = rate up to 1.152 Mbit/s - Only 76x
*/
/* EFR register bits */
#define SC16IS7XX_EFR_AUTORTS_BIT BIT(6) /* Auto RTS flow ctrl enable */
#define SC16IS7XX_EFR_AUTOCTS_BIT BIT(7) /* Auto CTS flow ctrl enable */
#define SC16IS7XX_EFR_XOFF2_DETECT_BIT BIT(5) /* Enable Xoff2 detection */
-#define SC16IS7XX_EFR_ENABLE_BIT BIT(4) /* Enable enhanced functions
- * and writing to IER[7:4],
- * FCR[5:4], MCR[7:5]
+#define SC16IS7XX_EFR_ENABLE_BIT BIT(4) /* Enable enhanced functions and writing to
+ * IER[7:4], FCR[5:4], MCR[7:5]
*/
#define SC16IS7XX_EFR_SWFLOW3_BIT BIT(3)
#define SC16IS7XX_EFR_SWFLOW2_BIT BIT(2)
/*
* SWFLOW bits 3 & 2 table:
- * 00 -> no transmitter flow
- * control
- * 01 -> transmitter generates
- * XON2 and XOFF2
- * 10 -> transmitter generates
- * XON1 and XOFF1
- * 11 -> transmitter generates
- * XON1, XON2, XOFF1 and
- * XOFF2
+ * 00 -> no transmitter flow control
+ * 01 -> transmitter generates XON2 and XOFF2
+ * 10 -> transmitter generates XON1 and XOFF1
+ * 11 -> transmitter generates XON1, XON2,
+ * XOFF1 and XOFF2
*/
#define SC16IS7XX_EFR_SWFLOW1_BIT BIT(1)
#define SC16IS7XX_EFR_SWFLOW0_BIT BIT(0)
/*
* SWFLOW bits 1 & 0 table:
- * 00 -> no received flow
- * control
- * 01 -> receiver compares
- * XON2 and XOFF2
- * 10 -> receiver compares
- * XON1 and XOFF1
- * 11 -> receiver compares
- * XON1, XON2, XOFF1 and
- * XOFF2
+ * 00 -> no received flow control
+ * 01 -> receiver compares XON2 and XOFF2
+ * 10 -> receiver compares XON1 and XOFF1
+ * 11 -> receiver compares XON1, XON2,
+ * XOFF1 and XOFF2
*/
#define SC16IS7XX_EFR_FLOWCTRL_BITS (SC16IS7XX_EFR_AUTORTS_BIT | \
SC16IS7XX_EFR_AUTOCTS_BIT | \
@@ -328,7 +288,7 @@ struct sc16is7xx_one_config {
struct sc16is7xx_one {
struct uart_port port;
struct regmap *regmap;
- struct mutex efr_lock; /* EFR registers access */
+ struct mutex lock; /* For registers sharing same address space. */
struct kthread_work tx_work;
struct kthread_work reg_work;
struct kthread_delayed_work ms_work;
@@ -358,16 +318,16 @@ static DEFINE_IDA(sc16is7xx_lines);
static struct uart_driver sc16is7xx_uart = {
.owner = THIS_MODULE,
- .driver_name = SC16IS7XX_NAME,
+ .driver_name = KBUILD_MODNAME,
.dev_name = "ttySC",
.nr = SC16IS7XX_MAX_DEVS,
};
-#define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e)))
+#define to_sc16is7xx_one(p) container_of((p), struct sc16is7xx_one, port)
static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
unsigned int val = 0;
regmap_read(one->regmap, reg, &val);
@@ -377,21 +337,21 @@ static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg)
static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
regmap_write(one->regmap, reg, val);
}
static void sc16is7xx_fifo_read(struct uart_port *port, u8 *rxbuf, unsigned int rxlen)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
regmap_noinc_read(one->regmap, SC16IS7XX_RHR_REG, rxbuf, rxlen);
}
static void sc16is7xx_fifo_write(struct uart_port *port, u8 *txbuf, u8 to_send)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
/*
* Don't send zero-length data, at least on SPI it confuses the chip
@@ -406,7 +366,7 @@ static void sc16is7xx_fifo_write(struct uart_port *port, u8 *txbuf, u8 to_send)
static void sc16is7xx_port_update(struct uart_port *port, u8 reg,
u8 mask, u8 val)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
regmap_update_bits(one->regmap, reg, mask, val);
}
@@ -419,52 +379,56 @@ static void sc16is7xx_power(struct uart_port *port, int on)
}
/*
- * In an amazing feat of design, the Enhanced Features Register (EFR)
- * shares the address of the Interrupt Identification Register (IIR).
- * Access to EFR is switched on by writing a magic value (0xbf) to the
- * Line Control Register (LCR). Any interrupt firing during this time will
- * see the EFR where it expects the IIR to be, leading to
+ * In an amazing feat of design, the enhanced register set shares the
+ * addresses 0x02 and 0x04-0x07 with the general register set.
+ * The special register set also shares the addresses 0x00-0x01 with the
+ * general register set.
+ *
+ * Access to the enhanced or special register set is enabled by writing a magic
+ * value to the Line Control Register (LCR). When enhanced register set access
+ * is enabled, for example, any interrupt firing during this time will see the
+ * EFR where it expects the IIR to be, leading to
* "Unexpected interrupt" messages.
*
- * Prevent this possibility by claiming a mutex while accessing the EFR,
- * and claiming the same mutex from within the interrupt handler. This is
- * similar to disabling the interrupt, but that doesn't work because the
- * bulk of the interrupt processing is run as a workqueue job in thread
- * context.
+ * Prevent this possibility by claiming a mutex when access to the enhanced
+ * or special register set is enabled, and claiming the same mutex from within
+ * the interrupt handler. This is similar to disabling the interrupt, but that
+ * doesn't work because the bulk of the interrupt processing is run as a
+ * workqueue job in thread context.
*/
-static void sc16is7xx_efr_lock(struct uart_port *port)
+static void sc16is7xx_regs_lock(struct uart_port *port, u8 register_set)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
- mutex_lock(&one->efr_lock);
+ mutex_lock(&one->lock);
/* Backup content of LCR. */
one->old_lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
- /* Enable access to Enhanced register set */
- sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_B);
+ /* Enable access to the desired register set */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, register_set);
- /* Disable cache updates when writing to EFR registers */
+ /* Disable cache updates when writing to non-general registers */
regcache_cache_bypass(one->regmap, true);
}
-static void sc16is7xx_efr_unlock(struct uart_port *port)
+static void sc16is7xx_regs_unlock(struct uart_port *port)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
- /* Re-enable cache updates when writing to normal registers */
+ /* Re-enable cache updates when writing to general registers */
regcache_cache_bypass(one->regmap, false);
/* Restore original content of LCR */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, one->old_lcr);
- mutex_unlock(&one->efr_lock);
+ mutex_unlock(&one->lock);
}
static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
lockdep_assert_held_once(&port->lock);
@@ -477,7 +441,7 @@ static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit)
static void sc16is7xx_ier_set(struct uart_port *port, u8 bit)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
lockdep_assert_held_once(&port->lock);
@@ -535,10 +499,11 @@ EXPORT_SYMBOL_GPL(sc16is762_devtype);
static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
- case SC16IS7XX_RHR_REG:
- case SC16IS7XX_IIR_REG:
- case SC16IS7XX_LSR_REG:
- case SC16IS7XX_MSR_REG:
+ case SC16IS7XX_RHR_REG: /* Shared address space with THR & DLL */
+ case SC16IS7XX_IIR_REG: /* Shared address space with FCR & EFR */
+ case SC16IS7XX_LSR_REG: /* Shared address space with XON2 */
+ case SC16IS7XX_MSR_REG: /* Shared address space with TCR & XOFF1 */
+ case SC16IS7XX_SPR_REG: /* Shared address space with TLR & XOFF2 */
case SC16IS7XX_TXLVL_REG:
case SC16IS7XX_RXLVL_REG:
case SC16IS7XX_IOSTATE_REG:
@@ -578,8 +543,6 @@ static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg)
*/
static int sc16is7xx_set_baud(struct uart_port *port, int baud)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- u8 lcr;
unsigned int prescaler = 1;
unsigned long clk = port->uartclk, div = clk / 16 / baud;
@@ -593,23 +556,15 @@ 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,
- SC16IS7XX_LCR_CONF_MODE_A);
+ /* Access special register set (DLL/DLH) */
+ sc16is7xx_regs_lock(port, SC16IS7XX_LCR_REG_SET_SPECIAL);
/* Write the new divisor */
- regcache_cache_bypass(one->regmap, true);
sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256);
sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256);
- regcache_cache_bypass(one->regmap, false);
- /* Restore LCR and access to general register set */
- sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
-
- mutex_unlock(&one->efr_lock);
+ /* Restore access to general register set */
+ sc16is7xx_regs_unlock(port);
return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div);
}
@@ -617,7 +572,7 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
unsigned int iir)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
unsigned int lsr = 0, bytes_read, i;
bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC);
u8 ch, flag;
@@ -756,7 +711,8 @@ static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)
unsigned long flags;
unsigned int status, changed;
- lockdep_assert_held_once(&one->efr_lock);
+ /* Lock required as MSR address is shared with TCR and XOFF1. */
+ lockdep_assert_held_once(&one->lock);
status = sc16is7xx_get_hwmctrl(port);
changed = status ^ one->old_mctrl;
@@ -782,18 +738,15 @@ static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)
static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
{
- bool rc = true;
unsigned int iir, rxlen;
struct uart_port *port = &s->p[portno].port;
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
- mutex_lock(&one->efr_lock);
+ guard(mutex)(&one->lock);
iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
- if (iir & SC16IS7XX_IIR_NO_INT_BIT) {
- rc = false;
- goto out_port_irq;
- }
+ if (iir & SC16IS7XX_IIR_NO_INT_BIT)
+ return false;
iir &= SC16IS7XX_IIR_ID_MASK;
@@ -833,18 +786,14 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
break;
}
-out_port_irq:
- mutex_unlock(&one->efr_lock);
-
- return rc;
+ return true;
}
static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
{
+ struct sc16is7xx_port *s = dev_id;
bool keep_polling;
- struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
-
do {
int i;
@@ -871,16 +820,15 @@ static void sc16is7xx_poll_proc(struct kthread_work *ws)
static void sc16is7xx_tx_proc(struct kthread_work *ws)
{
- struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = container_of(ws, struct sc16is7xx_one, tx_work);
+ struct uart_port *port = &one->port;
if ((port->rs485.flags & SER_RS485_ENABLED) &&
(port->rs485.delay_rts_before_send > 0))
msleep(port->rs485.delay_rts_before_send);
- mutex_lock(&one->efr_lock);
+ guard(mutex)(&one->lock);
sc16is7xx_handle_tx(port);
- mutex_unlock(&one->efr_lock);
}
static void sc16is7xx_reconf_rs485(struct uart_port *port)
@@ -905,7 +853,7 @@ static void sc16is7xx_reconf_rs485(struct uart_port *port)
static void sc16is7xx_reg_proc(struct kthread_work *ws)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(ws, reg_work);
+ struct sc16is7xx_one *one = container_of(ws, struct sc16is7xx_one, reg_work);
struct sc16is7xx_one_config config;
unsigned long irqflags;
@@ -943,13 +891,12 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws)
static void sc16is7xx_ms_proc(struct kthread_work *ws)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(ws, ms_work.work);
+ struct sc16is7xx_one *one = container_of(ws, struct sc16is7xx_one, ms_work.work);
struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);
if (one->port.state) {
- mutex_lock(&one->efr_lock);
- sc16is7xx_update_mlines(one);
- mutex_unlock(&one->efr_lock);
+ scoped_guard(mutex, &one->lock)
+ sc16is7xx_update_mlines(one);
kthread_queue_delayed_work(&s->kworker, &one->ms_work, HZ);
}
@@ -957,7 +904,7 @@ static void sc16is7xx_ms_proc(struct kthread_work *ws)
static void sc16is7xx_enable_ms(struct uart_port *port)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
lockdep_assert_held_once(&port->lock);
@@ -968,7 +915,7 @@ static void sc16is7xx_enable_ms(struct uart_port *port)
static void sc16is7xx_start_tx(struct uart_port *port)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
kthread_queue_work(&s->kworker, &one->tx_work);
}
@@ -1007,7 +954,7 @@ static unsigned int sc16is7xx_tx_empty(struct uart_port *port)
static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
/* Called with port lock taken so we can only return cached value */
return one->old_mctrl;
@@ -1016,7 +963,7 @@ static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
one->config.flags |= SC16IS7XX_RECONF_MD;
kthread_queue_work(&s->kworker, &one->reg_work);
@@ -1033,7 +980,7 @@ static void sc16is7xx_set_termios(struct uart_port *port,
struct ktermios *termios,
const struct ktermios *old)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
unsigned int lcr, flow = 0;
int baud;
unsigned long flags;
@@ -1106,12 +1053,12 @@ static void sc16is7xx_set_termios(struct uart_port *port,
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
/* Update EFR registers */
- sc16is7xx_efr_lock(port);
+ sc16is7xx_regs_lock(port, SC16IS7XX_LCR_REG_SET_ENHANCED);
sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]);
sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]);
sc16is7xx_port_update(port, SC16IS7XX_EFR_REG,
SC16IS7XX_EFR_FLOWCTRL_BITS, flow);
- sc16is7xx_efr_unlock(port);
+ sc16is7xx_regs_unlock(port);
/* Get baud rate generator configuration */
baud = uart_get_baud_rate(port, termios, old,
@@ -1136,7 +1083,7 @@ static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termi
struct serial_rs485 *rs485)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
if (rs485->flags & SER_RS485_ENABLED) {
/*
@@ -1156,14 +1103,14 @@ static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termi
static int sc16is7xx_startup(struct uart_port *port)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
unsigned int val;
unsigned long flags;
sc16is7xx_power(port, 1);
- /* Reset FIFOs*/
+ /* Reset FIFOs */
val = SC16IS7XX_FCR_RXRESET_BIT | SC16IS7XX_FCR_TXRESET_BIT;
sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, val);
udelay(5);
@@ -1191,8 +1138,7 @@ static int sc16is7xx_startup(struct uart_port *port)
/* This bit must be written with LCR[7] = 0 */
sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_IRDA_BIT,
- one->irda_mode ?
- SC16IS7XX_MCR_IRDA_BIT : 0);
+ one->irda_mode ? SC16IS7XX_MCR_IRDA_BIT : 0);
/* Enable the Rx and Tx FIFO */
sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
@@ -1220,7 +1166,7 @@ static int sc16is7xx_startup(struct uart_port *port)
static void sc16is7xx_shutdown(struct uart_port *port)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
kthread_cancel_delayed_work_sync(&one->ms_work);
@@ -1510,6 +1456,75 @@ static int sc16is7xx_reset(struct device *dev, struct regmap *regmap)
return 0;
}
+static int sc16is7xx_setup_channel(struct sc16is7xx_one *one, int i,
+ bool *port_registered)
+{
+ struct uart_port *port = &one->port;
+ int ret;
+
+ ret = ida_alloc_max(&sc16is7xx_lines, SC16IS7XX_MAX_DEVS - 1, GFP_KERNEL);
+ if (ret < 0)
+ return ret;
+
+ port->line = ret;
+
+ /* Initialize port data */
+ port->type = PORT_SC16IS7XX;
+ port->fifosize = SC16IS7XX_FIFO_SIZE;
+ port->flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
+ port->iobase = i;
+ /*
+ * Use all ones as membase to make sure uart_configure_port() in
+ * serial_core.c does not abort for SPI/I2C devices where the
+ * membase address is not applicable.
+ */
+ port->membase = (void __iomem *)~0;
+ port->iotype = UPIO_PORT;
+ port->rs485_config = sc16is7xx_config_rs485;
+ port->rs485_supported = sc16is7xx_rs485_supported;
+ port->ops = &sc16is7xx_ops;
+ one->old_mctrl = 0;
+
+ mutex_init(&one->lock);
+
+ ret = uart_get_rs485_mode(port);
+ if (ret)
+ return ret;
+
+ /* Enable access to general register set */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, 0x00);
+
+ /* Disable all interrupts */
+ sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0);
+ /* Disable TX/RX */
+ sc16is7xx_port_write(port, SC16IS7XX_EFCR_REG,
+ SC16IS7XX_EFCR_RXDISABLE_BIT |
+ SC16IS7XX_EFCR_TXDISABLE_BIT);
+
+ /* Initialize kthread work structs */
+ kthread_init_work(&one->tx_work, sc16is7xx_tx_proc);
+ kthread_init_work(&one->reg_work, sc16is7xx_reg_proc);
+ kthread_init_delayed_work(&one->ms_work, sc16is7xx_ms_proc);
+
+ /* Register port */
+ ret = uart_add_one_port(&sc16is7xx_uart, port);
+ if (ret)
+ return ret;
+
+ *port_registered = true;
+
+ sc16is7xx_regs_lock(port, SC16IS7XX_LCR_REG_SET_ENHANCED);
+ /* Enable write access to enhanced features */
+ sc16is7xx_port_write(port, SC16IS7XX_EFR_REG,
+ SC16IS7XX_EFR_ENABLE_BIT);
+ sc16is7xx_regs_unlock(port);
+
+ /* Go to suspend mode */
+ sc16is7xx_power(port, 0);
+
+ return 0;
+}
+
int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
struct regmap *regmaps[], int irq)
{
@@ -1539,10 +1554,8 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
/* Alloc port structure */
s = devm_kzalloc(dev, struct_size(s, p, devtype->nr_uart), GFP_KERNEL);
- if (!s) {
- dev_err(dev, "Error allocating port structure\n");
+ if (!s)
return -ENOMEM;
- }
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &uartclk);
@@ -1595,76 +1608,14 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
}
for (i = 0; i < devtype->nr_uart; ++i) {
- ret = ida_alloc_max(&sc16is7xx_lines,
- SC16IS7XX_MAX_DEVS - 1, GFP_KERNEL);
- if (ret < 0)
- goto out_ports;
-
- s->p[i].port.line = ret;
-
- /* Initialize port data */
s->p[i].port.dev = dev;
s->p[i].port.irq = irq;
- s->p[i].port.type = PORT_SC16IS7XX;
- s->p[i].port.fifosize = SC16IS7XX_FIFO_SIZE;
- s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
- s->p[i].port.iobase = i;
- /*
- * Use all ones as membase to make sure uart_configure_port() in
- * serial_core.c does not abort for SPI/I2C devices where the
- * membase address is not applicable.
- */
- s->p[i].port.membase = (void __iomem *)~0;
- s->p[i].port.iotype = UPIO_PORT;
s->p[i].port.uartclk = freq;
- s->p[i].port.rs485_config = sc16is7xx_config_rs485;
- s->p[i].port.rs485_supported = sc16is7xx_rs485_supported;
- s->p[i].port.ops = &sc16is7xx_ops;
- s->p[i].old_mctrl = 0;
s->p[i].regmap = regmaps[i];
- mutex_init(&s->p[i].efr_lock);
-
- ret = uart_get_rs485_mode(&s->p[i].port);
- if (ret)
- goto out_ports;
-
- /* Disable all interrupts */
- sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0);
- /* Disable TX/RX */
- sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG,
- SC16IS7XX_EFCR_RXDISABLE_BIT |
- SC16IS7XX_EFCR_TXDISABLE_BIT);
-
- /* Initialize kthread work structs */
- kthread_init_work(&s->p[i].tx_work, sc16is7xx_tx_proc);
- kthread_init_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
- kthread_init_delayed_work(&s->p[i].ms_work, sc16is7xx_ms_proc);
-
- /* Register port */
- ret = uart_add_one_port(&sc16is7xx_uart, &s->p[i].port);
+ ret = sc16is7xx_setup_channel(&s->p[i], i, &port_registered[i]);
if (ret)
goto out_ports;
-
- port_registered[i] = true;
-
- /* Enable EFR */
- sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG,
- SC16IS7XX_LCR_CONF_MODE_B);
-
- regcache_cache_bypass(regmaps[i], true);
-
- /* Enable write access to enhanced features */
- sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFR_REG,
- SC16IS7XX_EFR_ENABLE_BIT);
-
- regcache_cache_bypass(regmaps[i], false);
-
- /* Restore access to general registers */
- sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00);
-
- /* Go to suspend mode */
- sc16is7xx_power(&s->p[i].port, 0);
}
sc16is7xx_setup_irda_ports(s);
@@ -1814,4 +1765,4 @@ module_exit(sc16is7xx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>");
-MODULE_DESCRIPTION("SC16IS7xx tty serial core driver");
+MODULE_DESCRIPTION(KBUILD_MODNAME " tty serial core driver");
diff --git a/drivers/tty/serial/sc16is7xx.h b/drivers/tty/serial/sc16is7xx.h
index afb784eaee45..9c584d6d3593 100644
--- a/drivers/tty/serial/sc16is7xx.h
+++ b/drivers/tty/serial/sc16is7xx.h
@@ -8,7 +8,6 @@
#include <linux/regmap.h>
#include <linux/types.h>
-#define SC16IS7XX_NAME "sc16is7xx"
#define SC16IS7XX_MAX_PORTS 2 /* Maximum number of UART ports per IC. */
struct device;
diff --git a/drivers/tty/serial/sc16is7xx_i2c.c b/drivers/tty/serial/sc16is7xx_i2c.c
index cd7de9e057b8..699376c3b3a5 100644
--- a/drivers/tty/serial/sc16is7xx_i2c.c
+++ b/drivers/tty/serial/sc16is7xx_i2c.c
@@ -52,7 +52,7 @@ MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table);
static struct i2c_driver sc16is7xx_i2c_driver = {
.driver = {
- .name = SC16IS7XX_NAME,
+ .name = KBUILD_MODNAME,
.of_match_table = sc16is7xx_dt_ids,
},
.probe = sc16is7xx_i2c_probe,
@@ -63,5 +63,5 @@ static struct i2c_driver sc16is7xx_i2c_driver = {
module_i2c_driver(sc16is7xx_i2c_driver);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SC16IS7xx I2C interface driver");
+MODULE_DESCRIPTION(KBUILD_MODNAME " interface driver");
MODULE_IMPORT_NS("SERIAL_NXP_SC16IS7XX");
diff --git a/drivers/tty/serial/sc16is7xx_spi.c b/drivers/tty/serial/sc16is7xx_spi.c
index 20d736b657b1..7e76d0e38da7 100644
--- a/drivers/tty/serial/sc16is7xx_spi.c
+++ b/drivers/tty/serial/sc16is7xx_spi.c
@@ -75,7 +75,7 @@ MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table);
static struct spi_driver sc16is7xx_spi_driver = {
.driver = {
- .name = SC16IS7XX_NAME,
+ .name = KBUILD_MODNAME,
.of_match_table = sc16is7xx_dt_ids,
},
.probe = sc16is7xx_spi_probe,
@@ -86,5 +86,5 @@ static struct spi_driver sc16is7xx_spi_driver = {
module_spi_driver(sc16is7xx_spi_driver);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SC16IS7xx SPI interface driver");
+MODULE_DESCRIPTION(KBUILD_MODNAME " interface driver");
MODULE_IMPORT_NS("SERIAL_NXP_SC16IS7XX");
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 4757293ece8c..9930023e924c 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1034,9 +1034,8 @@ static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss)
{
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
- int retval;
- down_write(&tty->termios_rwsem);
+ guard(rwsem_write)(&tty->termios_rwsem);
/*
* This semaphore protects port->count. It is also
* very useful to prevent opens. Also, take the
@@ -1044,11 +1043,8 @@ static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss)
* module insertion/removal doesn't change anything
* under us.
*/
- mutex_lock(&port->mutex);
- retval = uart_set_info(tty, port, state, ss);
- mutex_unlock(&port->mutex);
- up_write(&tty->termios_rwsem);
- return retval;
+ guard(mutex)(&port->mutex);
+ return uart_set_info(tty, port, state, ss);
}
/**
@@ -1560,85 +1556,66 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
void __user *uarg = (void __user *)arg;
int ret = -ENOIOCTLCMD;
-
- /*
- * These ioctls don't rely on the hardware to be present.
- */
- switch (cmd) {
- case TIOCSERCONFIG:
- down_write(&tty->termios_rwsem);
- ret = uart_do_autoconfig(tty, state);
- up_write(&tty->termios_rwsem);
- break;
- }
-
- if (ret != -ENOIOCTLCMD)
- goto out;
-
- if (tty_io_error(tty)) {
- ret = -EIO;
- goto out;
+ /* This ioctl doesn't rely on the hardware to be present. */
+ if (cmd == TIOCSERCONFIG) {
+ guard(rwsem_write)(&tty->termios_rwsem);
+ return uart_do_autoconfig(tty, state);
}
- /*
- * The following should only be used when hardware is present.
- */
- switch (cmd) {
- case TIOCMIWAIT:
- ret = uart_wait_modem_status(state, arg);
- break;
- }
+ if (tty_io_error(tty))
+ return -EIO;
- if (ret != -ENOIOCTLCMD)
- goto out;
+ /* This should only be used when the hardware is present. */
+ if (cmd == TIOCMIWAIT)
+ return uart_wait_modem_status(state, arg);
/* rs485_config requires more locking than others */
if (cmd == TIOCSRS485)
down_write(&tty->termios_rwsem);
- mutex_lock(&port->mutex);
- uport = uart_port_check(state);
+ scoped_guard(mutex, &port->mutex) {
+ uport = uart_port_check(state);
- if (!uport || tty_io_error(tty)) {
- ret = -EIO;
- goto out_up;
- }
+ if (!uport || tty_io_error(tty)) {
+ ret = -EIO;
+ break;
+ }
- /*
- * All these rely on hardware being present and need to be
- * protected against the tty being hung up.
- */
+ /*
+ * All these rely on hardware being present and need to be
+ * protected against the tty being hung up.
+ */
- switch (cmd) {
- case TIOCSERGETLSR: /* Get line status register */
- ret = uart_get_lsr_info(tty, state, uarg);
- break;
+ switch (cmd) {
+ case TIOCSERGETLSR: /* Get line status register */
+ ret = uart_get_lsr_info(tty, state, uarg);
+ break;
- case TIOCGRS485:
- ret = uart_get_rs485_config(uport, uarg);
- break;
+ case TIOCGRS485:
+ ret = uart_get_rs485_config(uport, uarg);
+ break;
- case TIOCSRS485:
- ret = uart_set_rs485_config(tty, uport, uarg);
- break;
+ case TIOCSRS485:
+ ret = uart_set_rs485_config(tty, uport, uarg);
+ break;
- case TIOCSISO7816:
- ret = uart_set_iso7816_config(state->uart_port, uarg);
- break;
+ case TIOCSISO7816:
+ ret = uart_set_iso7816_config(state->uart_port, uarg);
+ break;
- case TIOCGISO7816:
- ret = uart_get_iso7816_config(state->uart_port, uarg);
- break;
- default:
- if (uport->ops->ioctl)
- ret = uport->ops->ioctl(uport, cmd, arg);
- break;
+ case TIOCGISO7816:
+ ret = uart_get_iso7816_config(state->uart_port, uarg);
+ break;
+ default:
+ if (uport->ops->ioctl)
+ ret = uport->ops->ioctl(uport, cmd, arg);
+ break;
+ }
}
-out_up:
- mutex_unlock(&port->mutex);
+
if (cmd == TIOCSRS485)
up_write(&tty->termios_rwsem);
-out:
+
return ret;
}
@@ -1651,11 +1628,10 @@ static void uart_set_ldisc(struct tty_struct *tty)
if (!tty_port_initialized(port))
return;
- mutex_lock(&state->port.mutex);
+ guard(mutex)(&state->port.mutex);
uport = uart_port_check(state);
if (uport && uport->ops->set_ldisc)
uport->ops->set_ldisc(uport, &tty->termios);
- mutex_unlock(&state->port.mutex);
}
static void uart_set_termios(struct tty_struct *tty,
@@ -1729,9 +1705,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
state = drv->state + tty->index;
port = &state->port;
- spin_lock_irq(&port->lock);
+ guard(spinlock_irq)(&port->lock);
--port->count;
- spin_unlock_irq(&port->lock);
return;
}
@@ -1843,20 +1818,18 @@ static void uart_hangup(struct tty_struct *tty)
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
struct uart_port *uport;
- unsigned long flags;
pr_debug("uart_hangup(%d)\n", tty->index);
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
uport = uart_port_check(state);
WARN(!uport, "hangup of detached port!\n");
if (tty_port_active(port)) {
uart_flush_buffer(tty);
uart_shutdown(tty, state);
- spin_lock_irqsave(&port->lock, flags);
- port->count = 0;
- spin_unlock_irqrestore(&port->lock, flags);
+ scoped_guard(spinlock_irqsave, &port->lock)
+ port->count = 0;
tty_port_set_active(port, false);
tty_port_tty_set(port, NULL);
if (uport && !uart_console(uport))
@@ -1864,7 +1837,6 @@ static void uart_hangup(struct tty_struct *tty)
wake_up_interruptible(&port->open_wait);
wake_up_interruptible(&port->delta_msr_wait);
}
- mutex_unlock(&port->mutex);
}
/* uport == NULL if uart_port has already been removed */
@@ -2969,11 +2941,11 @@ static ssize_t console_show(struct device *dev,
struct uart_port *uport;
bool console = false;
- mutex_lock(&port->mutex);
- uport = uart_port_check(state);
- if (uport)
- console = uart_console_registered(uport);
- mutex_unlock(&port->mutex);
+ scoped_guard(mutex, &port->mutex) {
+ uport = uart_port_check(state);
+ if (uport)
+ console = uart_console_registered(uport);
+ }
return sprintf(buf, "%c\n", console ? 'Y' : 'N');
}
@@ -3158,17 +3130,14 @@ static void serial_core_remove_one_port(struct uart_driver *drv,
struct tty_port *port = &state->port;
struct uart_port *uart_port;
- mutex_lock(&port->mutex);
- uart_port = uart_port_check(state);
- if (uart_port != uport)
- dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
- uart_port, uport);
+ scoped_guard(mutex, &port->mutex) {
+ uart_port = uart_port_check(state);
+ if (uart_port != uport)
+ dev_alert(uport->dev, "Removing wrong port: %p != %p\n", uart_port, uport);
- if (!uart_port) {
- mutex_unlock(&port->mutex);
- return;
+ if (!uart_port)
+ return;
}
- mutex_unlock(&port->mutex);
/*
* Remove the devices from the tty layer
@@ -3197,11 +3166,10 @@ static void serial_core_remove_one_port(struct uart_driver *drv,
uport->type = PORT_UNKNOWN;
uport->port_dev = NULL;
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
WARN_ON(atomic_dec_return(&state->refcount) < 0);
wait_event(state->remove_wait, !atomic_read(&state->refcount));
state->uart_port = NULL;
- mutex_unlock(&port->mutex);
}
/**
@@ -3354,7 +3322,7 @@ void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port
struct serial_ctrl_device *ctrl_dev = serial_core_get_ctrl_dev(port_dev);
int ctrl_id = port->ctrl_id;
- mutex_lock(&port_mutex);
+ guard(mutex)(&port_mutex);
port->flags |= UPF_DEAD;
@@ -3366,8 +3334,6 @@ void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port
/* Drop the serial core controller device if no ports are using it */
if (!serial_core_ctrl_find(drv, phys_dev, ctrl_id))
serial_base_ctrl_device_remove(ctrl_dev);
-
- mutex_unlock(&port_mutex);
}
/**
@@ -3536,6 +3502,14 @@ int uart_get_rs485_mode(struct uart_port *port)
if (!(port->rs485_supported.flags & SER_RS485_ENABLED))
return 0;
+ /*
+ * Retrieve properties only if a firmware node exists. If no firmware
+ * node exists, then don't touch rs485 config and keep initial rs485
+ * properties set by driver.
+ */
+ if (!dev_fwnode(dev))
+ return 0;
+
ret = device_property_read_u32_array(dev, "rs485-rts-delay",
rs485_delay, 2);
if (!ret) {
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 62bb62b82cbe..53edbf1d8963 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -17,29 +17,32 @@
*/
#undef DEBUG
+#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/console.h>
-#include <linux/ctype.h>
#include <linux/cpufreq.h>
+#include <linux/ctype.h>
#include <linux/delay.h>
-#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/ktime.h>
#include <linux/major.h>
#include <linux/minmax.h>
-#include <linux/module.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/scatterlist.h>
#include <linux/serial.h>
+#include <linux/serial_core.h>
#include <linux/serial_sci.h>
#include <linux/sh_dma.h>
#include <linux/slab.h>
@@ -50,15 +53,186 @@
#include <linux/tty_flip.h>
#ifdef CONFIG_SUPERH
-#include <asm/sh_bios.h>
#include <asm/platform_early.h>
+#include <asm/sh_bios.h>
#endif
#include "rsci.h"
#include "serial_mctrl_gpio.h"
-#include "sh-sci.h"
#include "sh-sci-common.h"
+#define SCI_MAJOR 204
+#define SCI_MINOR_START 8
+
+/*
+ * SCI register subset common for all port types.
+ * Not all registers will exist on all parts.
+ */
+enum {
+ SCSMR, /* Serial Mode Register */
+ SCBRR, /* Bit Rate Register */
+ SCSCR, /* Serial Control Register */
+ SCxSR, /* Serial Status Register */
+ SCFCR, /* FIFO Control Register */
+ SCFDR, /* FIFO Data Count Register */
+ SCxTDR, /* Transmit (FIFO) Data Register */
+ SCxRDR, /* Receive (FIFO) Data Register */
+ SCLSR, /* Line Status Register */
+ SCTFDR, /* Transmit FIFO Data Count Register */
+ SCRFDR, /* Receive FIFO Data Count Register */
+ SCSPTR, /* Serial Port Register */
+ HSSRR, /* Sampling Rate Register */
+ SCPCR, /* Serial Port Control Register */
+ SCPDR, /* Serial Port Data Register */
+ SCDL, /* BRG Frequency Division Register */
+ SCCKS, /* BRG Clock Select Register */
+ HSRTRGR, /* Rx FIFO Data Count Trigger Register */
+ HSTTRGR, /* Tx FIFO Data Count Trigger Register */
+ SEMR, /* Serial extended mode register */
+};
+
+/* SCSMR (Serial Mode Register) */
+#define SCSMR_C_A BIT(7) /* Communication Mode */
+#define SCSMR_CSYNC BIT(7) /* - Clocked synchronous mode */
+#define SCSMR_ASYNC 0 /* - Asynchronous mode */
+#define SCSMR_CHR BIT(6) /* 7-bit Character Length */
+#define SCSMR_PE BIT(5) /* Parity Enable */
+#define SCSMR_ODD BIT(4) /* Odd Parity */
+#define SCSMR_STOP BIT(3) /* Stop Bit Length */
+#define SCSMR_CKS 0x0003 /* Clock Select */
+
+/* Serial Mode Register, SCIFA/SCIFB only bits */
+#define SCSMR_CKEDG BIT(12) /* Transmit/Receive Clock Edge Select */
+#define SCSMR_SRC_MASK 0x0700 /* Sampling Control */
+#define SCSMR_SRC_16 0x0000 /* Sampling rate 1/16 */
+#define SCSMR_SRC_5 0x0100 /* Sampling rate 1/5 */
+#define SCSMR_SRC_7 0x0200 /* Sampling rate 1/7 */
+#define SCSMR_SRC_11 0x0300 /* Sampling rate 1/11 */
+#define SCSMR_SRC_13 0x0400 /* Sampling rate 1/13 */
+#define SCSMR_SRC_17 0x0500 /* Sampling rate 1/17 */
+#define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */
+#define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */
+
+/* Serial Control Register, SCI only bits */
+#define SCSCR_TEIE BIT(2) /* Transmit End Interrupt Enable */
+
+/* Serial Control Register, SCIFA/SCIFB only bits */
+#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */
+#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */
+
+/* Serial Control Register, HSCIF-only bits */
+#define HSSCR_TOT_SHIFT 14
+
+/* SCxSR (Serial Status Register) on SCI */
+#define SCI_TDRE BIT(7) /* Transmit Data Register Empty */
+#define SCI_RDRF BIT(6) /* Receive Data Register Full */
+#define SCI_ORER BIT(5) /* Overrun Error */
+#define SCI_FER BIT(4) /* Framing Error */
+#define SCI_PER BIT(3) /* Parity Error */
+#define SCI_TEND BIT(2) /* Transmit End */
+#define SCI_RESERVED 0x03 /* All reserved bits */
+
+#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
+
+#define SCI_RDxF_CLEAR (u32)(~(SCI_RESERVED | SCI_RDRF))
+#define SCI_ERROR_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
+#define SCI_TDxE_CLEAR (u32)(~(SCI_RESERVED | SCI_TEND | SCI_TDRE))
+#define SCI_BREAK_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
+
+/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */
+#define SCIF_ER BIT(7) /* Receive Error */
+#define SCIF_TEND BIT(6) /* Transmission End */
+#define SCIF_TDFE BIT(5) /* Transmit FIFO Data Empty */
+#define SCIF_BRK BIT(4) /* Break Detect */
+#define SCIF_FER BIT(3) /* Framing Error */
+#define SCIF_PER BIT(2) /* Parity Error */
+#define SCIF_RDF BIT(1) /* Receive FIFO Data Full */
+#define SCIF_DR BIT(0) /* Receive Data Ready */
+/* SCIF only (optional) */
+#define SCIF_PERC 0xf000 /* Number of Parity Errors */
+#define SCIF_FERC 0x0f00 /* Number of Framing Errors */
+/*SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 only */
+#define SCIFA_ORER BIT(9) /* Overrun Error */
+
+#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER)
+
+#define SCIF_RDxF_CLEAR (u32)(~(SCIF_DR | SCIF_RDF))
+#define SCIF_ERROR_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_ER))
+#define SCIF_TDxE_CLEAR (u32)(~(SCIF_TDFE))
+#define SCIF_BREAK_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_BRK))
+
+/* SCFCR (FIFO Control Register) */
+#define SCFCR_RTRG1 BIT(7) /* Receive FIFO Data Count Trigger */
+#define SCFCR_RTRG0 BIT(6)
+#define SCFCR_TTRG1 BIT(5) /* Transmit FIFO Data Count Trigger */
+#define SCFCR_TTRG0 BIT(4)
+#define SCFCR_MCE BIT(3) /* Modem Control Enable */
+#define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */
+#define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */
+#define SCFCR_LOOP BIT(0) /* Loopback Test */
+
+/* SCLSR (Line Status Register) on (H)SCIF */
+#define SCLSR_TO BIT(2) /* Timeout */
+#define SCLSR_ORER BIT(0) /* Overrun Error */
+
+/* SCSPTR (Serial Port Register), optional */
+#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS# Pin Input/Output */
+#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS# Pin Data */
+#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS# Pin Input/Output */
+#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS# Pin Data */
+#define SCSPTR_SCKIO BIT(3) /* Serial Port Clock Pin Input/Output */
+#define SCSPTR_SCKDT BIT(2) /* Serial Port Clock Pin Data */
+#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */
+#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */
+
+/* HSSRR HSCIF */
+#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */
+#define HSCIF_SRDE BIT(14) /* Sampling Point Register Enable */
+
+#define HSCIF_SRHP_SHIFT 8
+#define HSCIF_SRHP_MASK 0x0f00
+
+/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */
+#define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */
+#define SCPCR_CTSC BIT(3) /* Serial Port CTS# Pin / Input Pin */
+#define SCPCR_SCKC BIT(2) /* Serial Port SCK Pin / Output Pin */
+#define SCPCR_RXDC BIT(1) /* Serial Port RXD Pin / Input Pin */
+#define SCPCR_TXDC BIT(0) /* Serial Port TXD Pin / Output Pin */
+
+/* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */
+#define SCPDR_RTSD BIT(4) /* Serial Port RTS# Output Pin Data */
+#define SCPDR_CTSD BIT(3) /* Serial Port CTS# Input Pin Data */
+#define SCPDR_SCKD BIT(2) /* Serial Port SCK Output Pin Data */
+#define SCPDR_RXDD BIT(1) /* Serial Port RXD Input Pin Data */
+#define SCPDR_TXDD BIT(0) /* Serial Port TXD Output Pin Data */
+
+/*
+ * BRG Clock Select Register (Some SCIF and HSCIF)
+ * The Baud Rate Generator for external clock can provide a clock source for
+ * the sampling clock. It outputs either its frequency divided clock, or the
+ * (undivided) (H)SCK external clock.
+ */
+#define SCCKS_CKS BIT(15) /* Select (H)SCK (1) or divided SC_CLK (0) */
+#define SCCKS_XIN BIT(14) /* SC_CLK uses bus clock (1) or SCIF_CLK (0) */
+
+#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
+#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_DR | SCIF_RDF)
+#define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE)
+#define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER)
+#define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER)
+#define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK)
+
+#define SCxSR_ERRORS(port) (to_sci_port(port)->params->error_mask)
+
+#define SCxSR_RDxF_CLEAR(port) \
+ (((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR)
+#define SCxSR_ERROR_CLEAR(port) \
+ (to_sci_port(port)->params->error_clear)
+#define SCxSR_TDxE_CLEAR(port) \
+ (((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR)
+#define SCxSR_BREAK_CLEAR(port) \
+ (((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR)
+
#define SCIx_IRQ_IS_MUXED(port) \
((port)->irqs[SCIx_ERI_IRQ] == \
(port)->irqs[SCIx_RXI_IRQ]) || \
@@ -1024,8 +1198,16 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
status = s->ops->read_reg(port, s->params->overrun_reg);
if (status & s->params->overrun_mask) {
- status &= ~s->params->overrun_mask;
- s->ops->write_reg(port, s->params->overrun_reg, status);
+ if (s->type == SCI_PORT_RSCI) {
+ /*
+ * All of the CFCLR_*C clearing bits match the corresponding
+ * CSR_*status bits. So, reuse the overrun mask for clearing.
+ */
+ s->ops->clear_SCxSR(port, s->params->overrun_mask);
+ } else {
+ status &= ~s->params->overrun_mask;
+ s->ops->write_reg(port, s->params->overrun_reg, status);
+ }
port->icount.overrun++;
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
deleted file mode 100644
index 951681aba586..000000000000
--- a/drivers/tty/serial/sh-sci.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <linux/bitops.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-
-#define SCI_MAJOR 204
-#define SCI_MINOR_START 8
-
-
-/*
- * SCI register subset common for all port types.
- * Not all registers will exist on all parts.
- */
-enum {
- SCSMR, /* Serial Mode Register */
- SCBRR, /* Bit Rate Register */
- SCSCR, /* Serial Control Register */
- SCxSR, /* Serial Status Register */
- SCFCR, /* FIFO Control Register */
- SCFDR, /* FIFO Data Count Register */
- SCxTDR, /* Transmit (FIFO) Data Register */
- SCxRDR, /* Receive (FIFO) Data Register */
- SCLSR, /* Line Status Register */
- SCTFDR, /* Transmit FIFO Data Count Register */
- SCRFDR, /* Receive FIFO Data Count Register */
- SCSPTR, /* Serial Port Register */
- HSSRR, /* Sampling Rate Register */
- SCPCR, /* Serial Port Control Register */
- SCPDR, /* Serial Port Data Register */
- SCDL, /* BRG Frequency Division Register */
- SCCKS, /* BRG Clock Select Register */
- HSRTRGR, /* Rx FIFO Data Count Trigger Register */
- HSTTRGR, /* Tx FIFO Data Count Trigger Register */
- SEMR, /* Serial extended mode register */
-};
-
-
-/* SCSMR (Serial Mode Register) */
-#define SCSMR_C_A BIT(7) /* Communication Mode */
-#define SCSMR_CSYNC BIT(7) /* - Clocked synchronous mode */
-#define SCSMR_ASYNC 0 /* - Asynchronous mode */
-#define SCSMR_CHR BIT(6) /* 7-bit Character Length */
-#define SCSMR_PE BIT(5) /* Parity Enable */
-#define SCSMR_ODD BIT(4) /* Odd Parity */
-#define SCSMR_STOP BIT(3) /* Stop Bit Length */
-#define SCSMR_CKS 0x0003 /* Clock Select */
-
-/* Serial Mode Register, SCIFA/SCIFB only bits */
-#define SCSMR_CKEDG BIT(12) /* Transmit/Receive Clock Edge Select */
-#define SCSMR_SRC_MASK 0x0700 /* Sampling Control */
-#define SCSMR_SRC_16 0x0000 /* Sampling rate 1/16 */
-#define SCSMR_SRC_5 0x0100 /* Sampling rate 1/5 */
-#define SCSMR_SRC_7 0x0200 /* Sampling rate 1/7 */
-#define SCSMR_SRC_11 0x0300 /* Sampling rate 1/11 */
-#define SCSMR_SRC_13 0x0400 /* Sampling rate 1/13 */
-#define SCSMR_SRC_17 0x0500 /* Sampling rate 1/17 */
-#define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */
-#define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */
-
-/* Serial Control Register, SCI only bits */
-#define SCSCR_TEIE BIT(2) /* Transmit End Interrupt Enable */
-
-/* Serial Control Register, SCIFA/SCIFB only bits */
-#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */
-#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */
-
-/* Serial Control Register, HSCIF-only bits */
-#define HSSCR_TOT_SHIFT 14
-
-/* SCxSR (Serial Status Register) on SCI */
-#define SCI_TDRE BIT(7) /* Transmit Data Register Empty */
-#define SCI_RDRF BIT(6) /* Receive Data Register Full */
-#define SCI_ORER BIT(5) /* Overrun Error */
-#define SCI_FER BIT(4) /* Framing Error */
-#define SCI_PER BIT(3) /* Parity Error */
-#define SCI_TEND BIT(2) /* Transmit End */
-#define SCI_RESERVED 0x03 /* All reserved bits */
-
-#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
-
-#define SCI_RDxF_CLEAR (u32)(~(SCI_RESERVED | SCI_RDRF))
-#define SCI_ERROR_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
-#define SCI_TDxE_CLEAR (u32)(~(SCI_RESERVED | SCI_TEND | SCI_TDRE))
-#define SCI_BREAK_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
-
-/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */
-#define SCIF_ER BIT(7) /* Receive Error */
-#define SCIF_TEND BIT(6) /* Transmission End */
-#define SCIF_TDFE BIT(5) /* Transmit FIFO Data Empty */
-#define SCIF_BRK BIT(4) /* Break Detect */
-#define SCIF_FER BIT(3) /* Framing Error */
-#define SCIF_PER BIT(2) /* Parity Error */
-#define SCIF_RDF BIT(1) /* Receive FIFO Data Full */
-#define SCIF_DR BIT(0) /* Receive Data Ready */
-/* SCIF only (optional) */
-#define SCIF_PERC 0xf000 /* Number of Parity Errors */
-#define SCIF_FERC 0x0f00 /* Number of Framing Errors */
-/*SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 only */
-#define SCIFA_ORER BIT(9) /* Overrun Error */
-
-#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER)
-
-#define SCIF_RDxF_CLEAR (u32)(~(SCIF_DR | SCIF_RDF))
-#define SCIF_ERROR_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_ER))
-#define SCIF_TDxE_CLEAR (u32)(~(SCIF_TDFE))
-#define SCIF_BREAK_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_BRK))
-
-/* SCFCR (FIFO Control Register) */
-#define SCFCR_RTRG1 BIT(7) /* Receive FIFO Data Count Trigger */
-#define SCFCR_RTRG0 BIT(6)
-#define SCFCR_TTRG1 BIT(5) /* Transmit FIFO Data Count Trigger */
-#define SCFCR_TTRG0 BIT(4)
-#define SCFCR_MCE BIT(3) /* Modem Control Enable */
-#define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */
-#define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */
-#define SCFCR_LOOP BIT(0) /* Loopback Test */
-
-/* SCLSR (Line Status Register) on (H)SCIF */
-#define SCLSR_TO BIT(2) /* Timeout */
-#define SCLSR_ORER BIT(0) /* Overrun Error */
-
-/* SCSPTR (Serial Port Register), optional */
-#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS# Pin Input/Output */
-#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS# Pin Data */
-#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS# Pin Input/Output */
-#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS# Pin Data */
-#define SCSPTR_SCKIO BIT(3) /* Serial Port Clock Pin Input/Output */
-#define SCSPTR_SCKDT BIT(2) /* Serial Port Clock Pin Data */
-#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */
-#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */
-
-/* HSSRR HSCIF */
-#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */
-#define HSCIF_SRDE BIT(14) /* Sampling Point Register Enable */
-
-#define HSCIF_SRHP_SHIFT 8
-#define HSCIF_SRHP_MASK 0x0f00
-
-/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */
-#define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */
-#define SCPCR_CTSC BIT(3) /* Serial Port CTS# Pin / Input Pin */
-#define SCPCR_SCKC BIT(2) /* Serial Port SCK Pin / Output Pin */
-#define SCPCR_RXDC BIT(1) /* Serial Port RXD Pin / Input Pin */
-#define SCPCR_TXDC BIT(0) /* Serial Port TXD Pin / Output Pin */
-
-/* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */
-#define SCPDR_RTSD BIT(4) /* Serial Port RTS# Output Pin Data */
-#define SCPDR_CTSD BIT(3) /* Serial Port CTS# Input Pin Data */
-#define SCPDR_SCKD BIT(2) /* Serial Port SCK Output Pin Data */
-#define SCPDR_RXDD BIT(1) /* Serial Port RXD Input Pin Data */
-#define SCPDR_TXDD BIT(0) /* Serial Port TXD Output Pin Data */
-
-/*
- * BRG Clock Select Register (Some SCIF and HSCIF)
- * The Baud Rate Generator for external clock can provide a clock source for
- * the sampling clock. It outputs either its frequency divided clock, or the
- * (undivided) (H)SCK external clock.
- */
-#define SCCKS_CKS BIT(15) /* Select (H)SCK (1) or divided SC_CLK (0) */
-#define SCCKS_XIN BIT(14) /* SC_CLK uses bus clock (1) or SCIF_CLK (0) */
-
-#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
-#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_DR | SCIF_RDF)
-#define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE)
-#define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER)
-#define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER)
-#define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK)
-
-#define SCxSR_ERRORS(port) (to_sci_port(port)->params->error_mask)
-
-#define SCxSR_RDxF_CLEAR(port) \
- (((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR)
-#define SCxSR_ERROR_CLEAR(port) \
- (to_sci_port(port)->params->error_clear)
-#define SCxSR_TDxE_CLEAR(port) \
- (((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR)
-#define SCxSR_BREAK_CLEAR(port) \
- (((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR)
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 8c9366321f8e..092755f35683 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -1133,6 +1133,9 @@ static int sprd_clk_init(struct uart_port *uport)
clk_uart = devm_clk_get(uport->dev, "uart");
if (IS_ERR(clk_uart)) {
+ if (PTR_ERR(clk_uart) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
dev_warn(uport->dev, "uart%d can't get uart clock\n",
uport->line);
clk_uart = NULL;
@@ -1140,6 +1143,9 @@ static int sprd_clk_init(struct uart_port *uport)
clk_parent = devm_clk_get(uport->dev, "source");
if (IS_ERR(clk_parent)) {
+ if (PTR_ERR(clk_parent) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
dev_warn(uport->dev, "uart%d can't get source clock\n",
uport->line);
clk_parent = NULL;
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index a66b44d21fba..c793fc74c26b 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -190,7 +190,6 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
* @port: Pointer to the UART port
* @uartclk: Reference clock
* @pclk: APB clock
- * @cdns_uart_driver: Pointer to UART driver
* @baud: Current baud rate
* @clk_rate_change_nb: Notifier block for clock changes
* @quirks: Flags for RXBS support.
@@ -204,7 +203,6 @@ struct cdns_uart {
struct uart_port *port;
struct clk *uartclk;
struct clk *pclk;
- struct uart_driver *cdns_uart_driver;
unsigned int baud;
struct notifier_block clk_rate_change_nb;
u32 quirks;
@@ -1465,7 +1463,6 @@ static struct console cdns_uart_console = {
static int cdns_uart_suspend(struct device *device)
{
struct uart_port *port = dev_get_drvdata(device);
- struct cdns_uart *cdns_uart = port->private_data;
int may_wake;
may_wake = device_may_wakeup(device);
@@ -1489,7 +1486,7 @@ static int cdns_uart_suspend(struct device *device)
* Call the API provided in serial_core.c file which handles
* the suspend.
*/
- return uart_suspend_port(cdns_uart->cdns_uart_driver, port);
+ return uart_suspend_port(&cdns_uart_uart_driver, port);
}
/**
@@ -1550,7 +1547,7 @@ static int cdns_uart_resume(struct device *device)
uart_port_unlock_irqrestore(port, flags);
}
- return uart_resume_port(cdns_uart->cdns_uart_driver, port);
+ return uart_resume_port(&cdns_uart_uart_driver, port);
}
#endif /* ! CONFIG_PM_SLEEP */
static int __maybe_unused cdns_runtime_suspend(struct device *dev)
@@ -1686,8 +1683,6 @@ static int cdns_uart_probe(struct platform_device *pdev)
}
}
- cdns_uart_data->cdns_uart_driver = &cdns_uart_uart_driver;
-
match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
if (match && match->data) {
const struct cdns_platform_data *data = match->data;
@@ -1862,7 +1857,7 @@ err_out_clk_dis_pclk:
clk_disable_unprepare(cdns_uart_data->pclk);
err_out_unregister_driver:
if (!instances)
- uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
+ uart_unregister_driver(&cdns_uart_uart_driver);
return rc;
}
@@ -1880,7 +1875,7 @@ static void cdns_uart_remove(struct platform_device *pdev)
clk_notifier_unregister(cdns_uart_data->uartclk,
&cdns_uart_data->clk_rate_change_nb);
#endif
- uart_remove_one_port(cdns_uart_data->cdns_uart_driver, port);
+ uart_remove_one_port(&cdns_uart_uart_driver, port);
port->mapbase = 0;
clk_disable_unprepare(cdns_uart_data->uartclk);
clk_disable_unprepare(cdns_uart_data->pclk);
@@ -1896,7 +1891,7 @@ static void cdns_uart_remove(struct platform_device *pdev)
reset_control_assert(cdns_uart_data->rstc);
if (!--instances)
- uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
+ uart_unregister_driver(&cdns_uart_uart_driver);
}
static struct platform_driver cdns_uart_platform_driver = {
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 3865b10d2d43..9d591fb291fd 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -407,9 +407,9 @@ static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value);
static void msc_set_vcr(struct slgt_info *info);
-static int startup(struct slgt_info *info);
+static int startup_hw(struct slgt_info *info);
static int block_til_ready(struct tty_struct *tty, struct file * filp,struct slgt_info *info);
-static void shutdown(struct slgt_info *info);
+static void shutdown_hw(struct slgt_info *info);
static void program_hw(struct slgt_info *info);
static void change_params(struct slgt_info *info);
@@ -622,7 +622,7 @@ static int open(struct tty_struct *tty, struct file *filp)
if (info->port.count == 1) {
/* 1st open on this device, init hardware */
- retval = startup(info);
+ retval = startup_hw(info);
if (retval < 0) {
mutex_unlock(&info->port.mutex);
goto cleanup;
@@ -666,7 +666,7 @@ static void close(struct tty_struct *tty, struct file *filp)
flush_buffer(tty);
tty_ldisc_flush(tty);
- shutdown(info);
+ shutdown_hw(info);
mutex_unlock(&info->port.mutex);
tty_port_close_end(&info->port, tty);
@@ -687,7 +687,7 @@ static void hangup(struct tty_struct *tty)
flush_buffer(tty);
mutex_lock(&info->port.mutex);
- shutdown(info);
+ shutdown_hw(info);
spin_lock_irqsave(&info->port.lock, flags);
info->port.count = 0;
@@ -1445,7 +1445,7 @@ static int hdlcdev_open(struct net_device *dev)
spin_unlock_irqrestore(&info->netlock, flags);
/* claim resources and init adapter */
- if ((rc = startup(info)) != 0) {
+ if ((rc = startup_hw(info)) != 0) {
spin_lock_irqsave(&info->netlock, flags);
info->netcount=0;
spin_unlock_irqrestore(&info->netlock, flags);
@@ -1455,7 +1455,7 @@ static int hdlcdev_open(struct net_device *dev)
/* generic HDLC layer open processing */
rc = hdlc_open(dev);
if (rc) {
- shutdown(info);
+ shutdown_hw(info);
spin_lock_irqsave(&info->netlock, flags);
info->netcount = 0;
spin_unlock_irqrestore(&info->netlock, flags);
@@ -1499,7 +1499,7 @@ static int hdlcdev_close(struct net_device *dev)
netif_stop_queue(dev);
/* shutdown adapter and release resources */
- shutdown(info);
+ shutdown_hw(info);
hdlc_close(dev);
@@ -2328,7 +2328,7 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id)
return IRQ_HANDLED;
}
-static int startup(struct slgt_info *info)
+static int startup_hw(struct slgt_info *info)
{
DBGINFO(("%s startup\n", info->device_name));
@@ -2361,7 +2361,7 @@ static int startup(struct slgt_info *info)
/*
* called by close() and hangup() to shutdown hardware
*/
-static void shutdown(struct slgt_info *info)
+static void shutdown_hw(struct slgt_info *info)
{
unsigned long flags;
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 67271fc0b223..1a5673acd9b1 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -76,7 +76,7 @@ void tty_buffer_unlock_exclusive(struct tty_port *port)
mutex_unlock(&buf->lock);
if (restart)
- queue_work(system_unbound_wq, &buf->work);
+ queue_work(system_dfl_wq, &buf->work);
}
EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive);
@@ -530,7 +530,7 @@ void tty_flip_buffer_push(struct tty_port *port)
struct tty_bufhead *buf = &port->buf;
tty_flip_buffer_commit(buf->tail);
- queue_work(system_unbound_wq, &buf->work);
+ queue_work(system_dfl_wq, &buf->work);
}
EXPORT_SYMBOL(tty_flip_buffer_push);
@@ -560,7 +560,7 @@ int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
tty_flip_buffer_commit(buf->tail);
spin_unlock_irqrestore(&port->lock, flags);
- queue_work(system_unbound_wq, &buf->work);
+ queue_work(system_dfl_wq, &buf->work);
return size;
}
@@ -613,7 +613,7 @@ void tty_buffer_set_lock_subclass(struct tty_port *port)
bool tty_buffer_restart_work(struct tty_port *port)
{
- return queue_work(system_unbound_wq, &port->buf.work);
+ return queue_work(system_dfl_wq, &port->buf.work);
}
bool tty_buffer_cancel_work(struct tty_port *port)
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index ee1d9c448c7e..d65fc60dd7be 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -424,8 +424,6 @@ static void do_compute_shiftstate(void)
/* We still have to export this method to vt.c */
void vt_set_leds_compute_shiftstate(void)
{
- unsigned long flags;
-
/*
* When VT is switched, the keyboard led needs to be set once.
* Ensure that after the switch is completed, the state of the
@@ -434,9 +432,8 @@ void vt_set_leds_compute_shiftstate(void)
vt_switch = true;
set_leds();
- spin_lock_irqsave(&kbd_event_lock, flags);
+ guard(spinlock_irqsave)(&kbd_event_lock);
do_compute_shiftstate();
- spin_unlock_irqrestore(&kbd_event_lock, flags);
}
/*
@@ -625,13 +622,12 @@ static void fn_compose(struct vc_data *vc)
static void fn_spawn_con(struct vc_data *vc)
{
- spin_lock(&vt_spawn_con.lock);
+ guard(spinlock)(&vt_spawn_con.lock);
if (vt_spawn_con.pid)
if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) {
put_pid(vt_spawn_con.pid);
vt_spawn_con.pid = NULL;
}
- spin_unlock(&vt_spawn_con.lock);
}
static void fn_SAK(struct vc_data *vc)
@@ -762,13 +758,9 @@ static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
return;
if ((unsigned)value < ARRAY_SIZE(func_table)) {
- unsigned long flags;
-
- spin_lock_irqsave(&func_buf_lock, flags);
+ guard(spinlock_irqsave)(&func_buf_lock);
if (func_table[value])
puts_queue(vc, func_table[value]);
- spin_unlock_irqrestore(&func_buf_lock, flags);
-
} else
pr_err("k_fn called with value=%d\n", value);
}
@@ -1140,8 +1132,7 @@ static unsigned char getledstate(void)
void setledstate(struct kbd_struct *kb, unsigned int led)
{
- unsigned long flags;
- spin_lock_irqsave(&led_lock, flags);
+ guard(spinlock_irqsave)(&led_lock);
if (!(led & ~7)) {
ledioctl = led;
kb->ledmode = LED_SHOW_IOCTL;
@@ -1149,7 +1140,6 @@ void setledstate(struct kbd_struct *kb, unsigned int led)
kb->ledmode = LED_SHOW_FLAGS;
set_leds();
- spin_unlock_irqrestore(&led_lock, flags);
}
static inline unsigned char getleds(void)
@@ -1172,14 +1162,9 @@ static inline unsigned char getleds(void)
int vt_get_leds(unsigned int console, int flag)
{
struct kbd_struct *kb = &kbd_table[console];
- int ret;
- unsigned long flags;
- spin_lock_irqsave(&led_lock, flags);
- ret = vc_kbd_led(kb, flag);
- spin_unlock_irqrestore(&led_lock, flags);
-
- return ret;
+ guard(spinlock_irqsave)(&led_lock);
+ return vc_kbd_led(kb, flag);
}
EXPORT_SYMBOL_GPL(vt_get_leds);
@@ -1213,11 +1198,10 @@ void vt_set_led_state(unsigned int console, int leds)
void vt_kbd_con_start(unsigned int console)
{
struct kbd_struct *kb = &kbd_table[console];
- unsigned long flags;
- spin_lock_irqsave(&led_lock, flags);
+
+ guard(spinlock_irqsave)(&led_lock);
clr_vc_kbd_led(kb, VC_SCROLLOCK);
set_leds();
- spin_unlock_irqrestore(&led_lock, flags);
}
/**
@@ -1230,11 +1214,10 @@ void vt_kbd_con_start(unsigned int console)
void vt_kbd_con_stop(unsigned int console)
{
struct kbd_struct *kb = &kbd_table[console];
- unsigned long flags;
- spin_lock_irqsave(&led_lock, flags);
+
+ guard(spinlock_irqsave)(&led_lock);
set_vc_kbd_led(kb, VC_SCROLLOCK);
set_leds();
- spin_unlock_irqrestore(&led_lock, flags);
}
/*
@@ -1246,12 +1229,11 @@ void vt_kbd_con_stop(unsigned int console)
static void kbd_bh(struct tasklet_struct *unused)
{
unsigned int leds;
- unsigned long flags;
- spin_lock_irqsave(&led_lock, flags);
- leds = getleds();
- leds |= (unsigned int)kbd->lockstate << 8;
- spin_unlock_irqrestore(&led_lock, flags);
+ scoped_guard(spinlock_irqsave, &led_lock) {
+ leds = getleds();
+ leds |= (unsigned int)kbd->lockstate << 8;
+ }
if (vt_switch) {
ledstate = ~leds;
@@ -1525,15 +1507,13 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
unsigned int event_code, int value)
{
/* We are called with interrupts disabled, just take the lock */
- spin_lock(&kbd_event_lock);
-
- if (event_type == EV_MSC && event_code == MSC_RAW &&
- kbd_is_hw_raw(handle->dev))
- kbd_rawcode(value);
- if (event_type == EV_KEY && event_code <= KEY_MAX)
- kbd_keycode(event_code, value, kbd_is_hw_raw(handle->dev));
-
- spin_unlock(&kbd_event_lock);
+ scoped_guard(spinlock, &kbd_event_lock) {
+ if (event_type == EV_MSC && event_code == MSC_RAW &&
+ kbd_is_hw_raw(handle->dev))
+ kbd_rawcode(value);
+ if (event_type == EV_KEY && event_code <= KEY_MAX)
+ kbd_keycode(event_code, value, kbd_is_hw_raw(handle->dev));
+ }
tasklet_schedule(&keyboard_tasklet);
do_poke_blanked_console = 1;
@@ -1566,10 +1546,9 @@ static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
- struct input_handle *handle;
int error;
- handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+ struct input_handle __free(kfree) *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;
@@ -1579,18 +1558,18 @@ static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
error = input_register_handle(handle);
if (error)
- goto err_free_handle;
+ return error;
error = input_open_device(handle);
if (error)
goto err_unregister_handle;
+ retain_and_null_ptr(handle);
+
return 0;
err_unregister_handle:
input_unregister_handle(handle);
- err_free_handle:
- kfree(handle);
return error;
}
@@ -1681,77 +1660,64 @@ int __init kbd_init(void)
*/
int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
{
- unsigned long flags;
int asize;
- int ret = 0;
switch (cmd) {
case KDGKBDIACR:
{
struct kbdiacrs __user *a = udp;
- struct kbdiacr *dia;
int i;
- dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr),
- GFP_KERNEL);
+ struct kbdiacr __free(kfree) *dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr),
+ GFP_KERNEL);
if (!dia)
return -ENOMEM;
/* Lock the diacriticals table, make a copy and then
copy it after we unlock */
- spin_lock_irqsave(&kbd_event_lock, flags);
-
- asize = accent_table_size;
- for (i = 0; i < asize; i++) {
- dia[i].diacr = conv_uni_to_8bit(
- accent_table[i].diacr);
- dia[i].base = conv_uni_to_8bit(
- accent_table[i].base);
- dia[i].result = conv_uni_to_8bit(
- accent_table[i].result);
+ scoped_guard(spinlock_irqsave, &kbd_event_lock) {
+ asize = accent_table_size;
+ for (i = 0; i < asize; i++) {
+ dia[i].diacr = conv_uni_to_8bit(accent_table[i].diacr);
+ dia[i].base = conv_uni_to_8bit(accent_table[i].base);
+ dia[i].result = conv_uni_to_8bit(accent_table[i].result);
+ }
}
- spin_unlock_irqrestore(&kbd_event_lock, flags);
if (put_user(asize, &a->kb_cnt))
- ret = -EFAULT;
- else if (copy_to_user(a->kbdiacr, dia,
- asize * sizeof(struct kbdiacr)))
- ret = -EFAULT;
- kfree(dia);
- return ret;
+ return -EFAULT;
+ if (copy_to_user(a->kbdiacr, dia, asize * sizeof(struct kbdiacr)))
+ return -EFAULT;
+ return 0;
}
case KDGKBDIACRUC:
{
struct kbdiacrsuc __user *a = udp;
- void *buf;
- buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc),
- GFP_KERNEL);
+ void __free(kfree) *buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc),
+ GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
/* Lock the diacriticals table, make a copy and then
copy it after we unlock */
- spin_lock_irqsave(&kbd_event_lock, flags);
-
- asize = accent_table_size;
- memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc));
-
- spin_unlock_irqrestore(&kbd_event_lock, flags);
+ scoped_guard(spinlock_irqsave, &kbd_event_lock) {
+ asize = accent_table_size;
+ memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc));
+ }
if (put_user(asize, &a->kb_cnt))
- ret = -EFAULT;
- else if (copy_to_user(a->kbdiacruc, buf,
- asize*sizeof(struct kbdiacruc)))
- ret = -EFAULT;
- kfree(buf);
- return ret;
+ return -EFAULT;
+ if (copy_to_user(a->kbdiacruc, buf, asize * sizeof(struct kbdiacruc)))
+ return -EFAULT;
+
+ return 0;
}
case KDSKBDIACR:
{
struct kbdiacrs __user *a = udp;
- struct kbdiacr *dia = NULL;
+ struct kbdiacr __free(kfree) *dia = NULL;
unsigned int ct;
int i;
@@ -1769,7 +1735,7 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
return PTR_ERR(dia);
}
- spin_lock_irqsave(&kbd_event_lock, flags);
+ guard(spinlock_irqsave)(&kbd_event_lock);
accent_table_size = ct;
for (i = 0; i < ct; i++) {
accent_table[i].diacr =
@@ -1779,8 +1745,7 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
accent_table[i].result =
conv_8bit_to_uni(dia[i].result);
}
- spin_unlock_irqrestore(&kbd_event_lock, flags);
- kfree(dia);
+
return 0;
}
@@ -1788,7 +1753,7 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
{
struct kbdiacrsuc __user *a = udp;
unsigned int ct;
- void *buf = NULL;
+ void __free(kfree) *buf = NULL;
if (!perm)
return -EPERM;
@@ -1804,18 +1769,16 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
ct, sizeof(struct kbdiacruc));
if (IS_ERR(buf))
return PTR_ERR(buf);
- }
- spin_lock_irqsave(&kbd_event_lock, flags);
+ }
+ guard(spinlock_irqsave)(&kbd_event_lock);
if (ct)
memcpy(accent_table, buf,
ct * sizeof(struct kbdiacruc));
accent_table_size = ct;
- spin_unlock_irqrestore(&kbd_event_lock, flags);
- kfree(buf);
return 0;
}
}
- return ret;
+ return 0;
}
/**
@@ -1829,33 +1792,29 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
int vt_do_kdskbmode(unsigned int console, unsigned int arg)
{
struct kbd_struct *kb = &kbd_table[console];
- int ret = 0;
- unsigned long flags;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ guard(spinlock_irqsave)(&kbd_event_lock);
switch(arg) {
case K_RAW:
kb->kbdmode = VC_RAW;
- break;
+ return 0;
case K_MEDIUMRAW:
kb->kbdmode = VC_MEDIUMRAW;
- break;
+ return 0;
case K_XLATE:
kb->kbdmode = VC_XLATE;
do_compute_shiftstate();
- break;
+ return 0;
case K_UNICODE:
kb->kbdmode = VC_UNICODE;
do_compute_shiftstate();
- break;
+ return 0;
case K_OFF:
kb->kbdmode = VC_OFF;
- break;
+ return 0;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
- spin_unlock_irqrestore(&kbd_event_lock, flags);
- return ret;
}
/**
@@ -1869,75 +1828,68 @@ int vt_do_kdskbmode(unsigned int console, unsigned int arg)
int vt_do_kdskbmeta(unsigned int console, unsigned int arg)
{
struct kbd_struct *kb = &kbd_table[console];
- int ret = 0;
- unsigned long flags;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ guard(spinlock_irqsave)(&kbd_event_lock);
switch(arg) {
case K_METABIT:
clr_vc_kbd_mode(kb, VC_META);
- break;
+ return 0;
case K_ESCPREFIX:
set_vc_kbd_mode(kb, VC_META);
- break;
+ return 0;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
- spin_unlock_irqrestore(&kbd_event_lock, flags);
- return ret;
}
-int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
- int perm)
+int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
{
struct kbkeycode tmp;
- int kc = 0;
+ int kc;
if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
return -EFAULT;
+
switch (cmd) {
case KDGETKEYCODE:
kc = getkeycode(tmp.scancode);
- if (kc >= 0)
- kc = put_user(kc, &user_kbkc->keycode);
- break;
+ if (kc < 0)
+ return kc;
+ return put_user(kc, &user_kbkc->keycode);
case KDSETKEYCODE:
if (!perm)
return -EPERM;
- kc = setkeycode(tmp.scancode, tmp.keycode);
- break;
+ return setkeycode(tmp.scancode, tmp.keycode);
}
- return kc;
+
+ return 0;
}
static unsigned short vt_kdgkbent(unsigned char kbdmode, unsigned char idx,
unsigned char map)
{
- unsigned short *key_map, val;
- unsigned long flags;
+ unsigned short *key_map;
/* Ensure another thread doesn't free it under us */
- spin_lock_irqsave(&kbd_event_lock, flags);
+ guard(spinlock_irqsave)(&kbd_event_lock);
key_map = key_maps[map];
if (key_map) {
- val = U(key_map[idx]);
+ unsigned short val = U(key_map[idx]);
if (kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
- val = K_HOLE;
- } else
- val = idx ? K_HOLE : K_NOSUCHMAP;
- spin_unlock_irqrestore(&kbd_event_lock, flags);
+ return K_HOLE;
+ return val;
+ }
- return val;
+ return idx ? K_HOLE : K_NOSUCHMAP;
}
static int vt_kdskbent(unsigned char kbdmode, unsigned char idx,
unsigned char map, unsigned short val)
{
- unsigned long flags;
- unsigned short *key_map, *new_map, oldval;
+ unsigned short *key_map, oldval;
if (!idx && val == K_NOSUCHMAP) {
- spin_lock_irqsave(&kbd_event_lock, flags);
+ guard(spinlock_irqsave)(&kbd_event_lock);
/* deallocate map */
key_map = key_maps[map];
if (map && key_map) {
@@ -1947,7 +1899,6 @@ static int vt_kdskbent(unsigned char kbdmode, unsigned char idx,
keymap_count--;
}
}
- spin_unlock_irqrestore(&kbd_event_lock, flags);
return 0;
}
@@ -1965,45 +1916,36 @@ static int vt_kdskbent(unsigned char kbdmode, unsigned char idx,
return 0;
#endif
- new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
+ unsigned short __free(kfree) *new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
if (!new_map)
return -ENOMEM;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ guard(spinlock_irqsave)(&kbd_event_lock);
key_map = key_maps[map];
if (key_map == NULL) {
int j;
- if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
- !capable(CAP_SYS_RESOURCE)) {
- spin_unlock_irqrestore(&kbd_event_lock, flags);
- kfree(new_map);
+ if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && !capable(CAP_SYS_RESOURCE))
return -EPERM;
- }
- key_maps[map] = new_map;
- key_map = new_map;
+
+ key_map = key_maps[map] = no_free_ptr(new_map);
key_map[0] = U(K_ALLOCATED);
for (j = 1; j < NR_KEYS; j++)
key_map[j] = U(K_HOLE);
keymap_count++;
- } else
- kfree(new_map);
+ }
oldval = U(key_map[idx]);
if (val == oldval)
- goto out;
+ return 0;
/* Attention Key */
- if ((oldval == K_SAK || val == K_SAK) && !capable(CAP_SYS_ADMIN)) {
- spin_unlock_irqrestore(&kbd_event_lock, flags);
+ if ((oldval == K_SAK || val == K_SAK) && !capable(CAP_SYS_ADMIN))
return -EPERM;
- }
key_map[idx] = U(val);
if (!map && (KTYP(oldval) == KT_SHIFT || KTYP(val) == KT_SHIFT))
do_compute_shiftstate();
-out:
- spin_unlock_irqrestore(&kbd_event_lock, flags);
return 0;
}
@@ -2049,9 +1991,6 @@ static char *vt_kdskbsent(char *kbs, unsigned char cur)
int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
{
unsigned char kb_func;
- unsigned long flags;
- char *kbs;
- int ret;
if (get_user(kb_func, &user_kdgkb->kb_func))
return -EFAULT;
@@ -2063,57 +2002,50 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
/* size should have been a struct member */
ssize_t len = sizeof(user_kdgkb->kb_string);
- kbs = kmalloc(len, GFP_KERNEL);
+ char __free(kfree) *kbs = kmalloc(len, GFP_KERNEL);
if (!kbs)
return -ENOMEM;
- spin_lock_irqsave(&func_buf_lock, flags);
- len = strscpy(kbs, func_table[kb_func] ? : "", len);
- spin_unlock_irqrestore(&func_buf_lock, flags);
+ scoped_guard(spinlock_irqsave, &func_buf_lock)
+ len = strscpy(kbs, func_table[kb_func] ? : "", len);
- if (len < 0) {
- ret = -ENOSPC;
- break;
- }
- ret = copy_to_user(user_kdgkb->kb_string, kbs, len + 1) ?
- -EFAULT : 0;
- break;
+ if (len < 0)
+ return -ENOSPC;
+
+ if (copy_to_user(user_kdgkb->kb_string, kbs, len + 1))
+ return -EFAULT;
+
+ return 0;
}
case KDSKBSENT:
if (!perm || !capable(CAP_SYS_TTY_CONFIG))
return -EPERM;
- kbs = strndup_user(user_kdgkb->kb_string,
- sizeof(user_kdgkb->kb_string));
+ char __free(kfree) *kbs = strndup_user(user_kdgkb->kb_string,
+ sizeof(user_kdgkb->kb_string));
if (IS_ERR(kbs))
return PTR_ERR(kbs);
- spin_lock_irqsave(&func_buf_lock, flags);
+ guard(spinlock_irqsave)(&func_buf_lock);
kbs = vt_kdskbsent(kbs, kb_func);
- spin_unlock_irqrestore(&func_buf_lock, flags);
- ret = 0;
- break;
+ return 0;
}
- kfree(kbs);
-
- return ret;
+ return 0;
}
int vt_do_kdskled(unsigned int console, int cmd, unsigned long arg, int perm)
{
struct kbd_struct *kb = &kbd_table[console];
- unsigned long flags;
unsigned char ucval;
switch(cmd) {
/* the ioctls below read/set the flags usually shown in the leds */
/* don't use them - they will go away without warning */
case KDGKBLED:
- spin_lock_irqsave(&kbd_event_lock, flags);
- ucval = kb->ledflagstate | (kb->default_ledflagstate << 4);
- spin_unlock_irqrestore(&kbd_event_lock, flags);
+ scoped_guard(spinlock_irqsave, &kbd_event_lock)
+ ucval = kb->ledflagstate | (kb->default_ledflagstate << 4);
return put_user(ucval, (char __user *)arg);
case KDSKBLED:
@@ -2121,11 +2053,11 @@ int vt_do_kdskled(unsigned int console, int cmd, unsigned long arg, int perm)
return -EPERM;
if (arg & ~0x77)
return -EINVAL;
- spin_lock_irqsave(&led_lock, flags);
- kb->ledflagstate = (arg & 7);
- kb->default_ledflagstate = ((arg >> 4) & 7);
- set_leds();
- spin_unlock_irqrestore(&led_lock, flags);
+ scoped_guard(spinlock_irqsave, &led_lock) {
+ kb->ledflagstate = (arg & 7);
+ kb->default_ledflagstate = ((arg >> 4) & 7);
+ set_leds();
+ }
return 0;
/* the ioctls below only set the lights, not the functions */
@@ -2182,11 +2114,8 @@ int vt_do_kdgkbmeta(unsigned int console)
*/
void vt_reset_unicode(unsigned int console)
{
- unsigned long flags;
-
- spin_lock_irqsave(&kbd_event_lock, flags);
+ guard(spinlock_irqsave)(&kbd_event_lock);
kbd_table[console].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
- spin_unlock_irqrestore(&kbd_event_lock, flags);
}
/**
@@ -2211,22 +2140,19 @@ int vt_get_shift_state(void)
void vt_reset_keyboard(unsigned int console)
{
struct kbd_struct *kb = &kbd_table[console];
- unsigned long flags;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ guard(spinlock_irqsave)(&kbd_event_lock);
set_vc_kbd_mode(kb, VC_REPEAT);
clr_vc_kbd_mode(kb, VC_CKMODE);
clr_vc_kbd_mode(kb, VC_APPLIC);
clr_vc_kbd_mode(kb, VC_CRLF);
kb->lockstate = 0;
kb->slockstate = 0;
- spin_lock(&led_lock);
+ guard(spinlock)(&led_lock);
kb->ledmode = LED_SHOW_FLAGS;
kb->ledflagstate = kb->default_ledflagstate;
- spin_unlock(&led_lock);
/* do not do set_leds here because this causes an endless tasklet loop
when the keyboard hasn't been initialized yet */
- spin_unlock_irqrestore(&kbd_event_lock, flags);
}
/**
@@ -2256,11 +2182,9 @@ int vt_get_kbd_mode_bit(unsigned int console, int bit)
void vt_set_kbd_mode_bit(unsigned int console, int bit)
{
struct kbd_struct *kb = &kbd_table[console];
- unsigned long flags;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ guard(spinlock_irqsave)(&kbd_event_lock);
set_vc_kbd_mode(kb, bit);
- spin_unlock_irqrestore(&kbd_event_lock, flags);
}
/**
@@ -2275,9 +2199,7 @@ void vt_set_kbd_mode_bit(unsigned int console, int bit)
void vt_clr_kbd_mode_bit(unsigned int console, int bit)
{
struct kbd_struct *kb = &kbd_table[console];
- unsigned long flags;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ guard(spinlock_irqsave)(&kbd_event_lock);
clr_vc_kbd_mode(kb, bit);
- spin_unlock_irqrestore(&kbd_event_lock, flags);
}
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 07d3b93975d3..13f4e48b4142 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -348,10 +348,11 @@ static int vc_selection(struct vc_data *vc, struct tiocl_selection *v,
return 0;
}
- v->xs = min_t(u16, v->xs - 1, vc->vc_cols - 1);
- v->ys = min_t(u16, v->ys - 1, vc->vc_rows - 1);
- v->xe = min_t(u16, v->xe - 1, vc->vc_cols - 1);
- v->ye = min_t(u16, v->ye - 1, vc->vc_rows - 1);
+ /* Historically 0 => max value */
+ v->xs = umin(v->xs - 1, vc->vc_cols - 1);
+ v->ys = umin(v->ys - 1, vc->vc_rows - 1);
+ v->xe = umin(v->xe - 1, vc->vc_cols - 1);
+ v->ye = umin(v->ye - 1, vc->vc_rows - 1);
if (mouse_reporting() && (v->sel_mode & TIOCL_SELMOUSEREPORT)) {
mouse_report(tty, v->sel_mode & TIOCL_SELBUTTONMASK, v->xs,
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 6e0089b85c27..59b4b5e126ba 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -4862,7 +4862,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
return ret;
}
- c = (font.width+7)/8 * vpitch * font.charcount;
+ c = DIV_ROUND_UP(font.width, 8) * vpitch * font.charcount;
if (op->data && font.charcount > op->charcount)
return -ENOSPC;
@@ -4894,7 +4894,7 @@ static int con_font_set(struct vc_data *vc, const struct console_font_op *op)
return -EINVAL;
if (vpitch < op->height)
return -EINVAL;
- size = (op->width+7)/8 * vpitch * op->charcount;
+ size = DIV_ROUND_UP(op->width, 8) * vpitch * op->charcount;
if (size > max_font_size)
return -ENOSPC;