Merge 6.17-rc6 into tty-next
We need the tty/serial fixes in here as well.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/Documentation/devicetree/bindings/serial/8250_omap.yaml b/Documentation/devicetree/bindings/serial/8250_omap.yaml
index 1859f712..aabacca 100644
--- a/Documentation/devicetree/bindings/serial/8250_omap.yaml
+++ b/Documentation/devicetree/bindings/serial/8250_omap.yaml
@@ -71,6 +71,22 @@
overrun-throttle-ms: true
wakeup-source: true
+ pinctrl-0:
+ description: Default pinctrl state
+
+ pinctrl-1:
+ description: Wakeup pinctrl state
+
+ pinctrl-names:
+ description:
+ When present should contain at least "default" describing the default pin
+ states. The second state called "wakeup" describes the pins in their
+ wakeup configuration required to exit sleep states.
+ minItems: 1
+ items:
+ - const: default
+ - const: wakeup
+
required:
- compatible
- reg
diff --git a/arch/mips/sgi-ip22/ip22-platform.c b/arch/mips/sgi-ip22/ip22-platform.c
index 0b2002e..3a53690 100644
--- a/arch/mips/sgi-ip22/ip22-platform.c
+++ b/arch/mips/sgi-ip22/ip22-platform.c
@@ -221,3 +221,35 @@ static int __init sgi_ds1286_devinit(void)
}
device_initcall(sgi_ds1286_devinit);
+
+#define SGI_ZILOG_BASE (HPC3_CHIP0_BASE + \
+ offsetof(struct hpc3_regs, pbus_extregs[6]) + \
+ offsetof(struct sgioc_regs, uart))
+
+static struct resource sgi_zilog_resources[] = {
+ {
+ .start = SGI_ZILOG_BASE,
+ .end = SGI_ZILOG_BASE + 15,
+ .flags = IORESOURCE_MEM
+ },
+ {
+ .start = SGI_SERIAL_IRQ,
+ .end = SGI_SERIAL_IRQ,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct platform_device zilog_device = {
+ .name = "ip22zilog",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(sgi_zilog_resources),
+ .resource = sgi_zilog_resources,
+};
+
+
+static int __init sgi_zilog_devinit(void)
+{
+ return platform_device_register(&zilog_device);
+}
+
+device_initcall(sgi_zilog_devinit);
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index b78b86e..a367f95 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -970,8 +970,6 @@ static void tty3270_resize(struct raw3270_view *view,
char **old_rcl_lines, **new_rcl_lines;
char *old_prompt, *new_prompt;
char *old_input, *new_input;
- struct tty_struct *tty;
- struct winsize ws;
size_t prompt_sz;
int new_allocated, old_allocated = tp->allocated_lines;
@@ -1023,14 +1021,14 @@ static void tty3270_resize(struct raw3270_view *view,
kfree(old_prompt);
tty3270_free_recall(old_rcl_lines);
tty3270_set_timer(tp, 1);
- /* Informat tty layer about new size */
- tty = tty_port_tty_get(&tp->port);
- if (!tty)
- return;
- ws.ws_row = tty3270_tty_rows(tp);
- ws.ws_col = tp->view.cols;
- tty_do_resize(tty, &ws);
- tty_kref_put(tty);
+ /* Inform the tty layer about new size */
+ scoped_guard(tty_port_tty, &tp->port) {
+ struct winsize ws = {
+ .ws_row = tty3270_tty_rows(tp),
+ .ws_col = tp->view.cols,
+ };
+ tty_do_resize(scoped_tty(), &ws);
+ }
return;
out_screen:
tty3270_free_screen(screen, new_rows);
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 13c663a..6b58f34 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -184,7 +184,7 @@ static void hvc_console_print(struct console *co, const char *b,
hvc_console_flush(cons_ops[index],
vtermnos[index]);
}
- } else if (r > 0) {
+ } else {
i -= r;
if (i > 0)
memmove(c, c+r, i);
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 2fc13cc..94677fe 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -442,11 +442,8 @@ static void __mxser_start_tx(struct mxser_port *info)
static void mxser_start_tx(struct mxser_port *info)
{
- unsigned long flags;
-
- spin_lock_irqsave(&info->slock, flags);
+ guard(spinlock_irqsave)(&info->slock);
__mxser_start_tx(info);
- spin_unlock_irqrestore(&info->slock, flags);
}
static void __mxser_stop_tx(struct mxser_port *info)
@@ -465,17 +462,15 @@ static bool mxser_carrier_raised(struct tty_port *port)
static void mxser_dtr_rts(struct tty_port *port, bool active)
{
struct mxser_port *mp = container_of(port, struct mxser_port, port);
- unsigned long flags;
u8 mcr;
- spin_lock_irqsave(&mp->slock, flags);
+ guard(spinlock_irqsave)(&mp->slock);
mcr = inb(mp->ioaddr + UART_MCR);
if (active)
mcr |= UART_MCR_DTR | UART_MCR_RTS;
else
mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
outb(mcr, mp->ioaddr + UART_MCR);
- spin_unlock_irqrestore(&mp->slock, flags);
}
static int mxser_set_baud(struct tty_struct *tty, speed_t newspd)
@@ -828,32 +823,28 @@ static void mxser_stop_rx(struct mxser_port *info)
static void mxser_shutdown_port(struct tty_port *port)
{
struct mxser_port *info = container_of(port, struct mxser_port, port);
- unsigned long flags;
- spin_lock_irqsave(&info->slock, flags);
+ scoped_guard(spinlock_irqsave, &info->slock) {
+ mxser_stop_rx(info);
- mxser_stop_rx(info);
+ /*
+ * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+ * here so the queue might never be waken up
+ */
+ wake_up_interruptible(&info->port.delta_msr_wait);
- /*
- * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
- * here so the queue might never be waken up
- */
- wake_up_interruptible(&info->port.delta_msr_wait);
+ info->IER = 0;
+ outb(0x00, info->ioaddr + UART_IER);
- info->IER = 0;
- outb(0x00, info->ioaddr + UART_IER);
+ /* clear Rx/Tx FIFO's */
+ mxser_disable_and_clear_FIFO(info);
- /* clear Rx/Tx FIFO's */
- mxser_disable_and_clear_FIFO(info);
+ /* read data port to reset things */
+ (void)inb(info->ioaddr + UART_RX);
- /* read data port to reset things */
- (void) inb(info->ioaddr + UART_RX);
-
-
- if (info->board->must_hwid)
- mxser_must_no_sw_flow_control(info->ioaddr);
-
- spin_unlock_irqrestore(&info->slock, flags);
+ if (info->board->must_hwid)
+ mxser_must_no_sw_flow_control(info->ioaddr);
+ }
/* make sure ISR is not running while we free the buffer */
synchronize_irq(info->board->irq);
@@ -880,15 +871,13 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
static void mxser_flush_buffer(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
- unsigned long flags;
- spin_lock_irqsave(&info->slock, flags);
- kfifo_reset(&info->port.xmit_fifo);
+ scoped_guard(spinlock_irqsave, &info->slock) {
+ kfifo_reset(&info->port.xmit_fifo);
- outb(info->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
- info->ioaddr + UART_FCR);
-
- spin_unlock_irqrestore(&info->slock, flags);
+ outb(info->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+ info->ioaddr + UART_FCR);
+ }
tty_wakeup(tty);
}
@@ -901,14 +890,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
static ssize_t mxser_write(struct tty_struct *tty, const u8 *buf, size_t count)
{
struct mxser_port *info = tty->driver_data;
- unsigned long flags;
size_t written;
bool is_empty;
- spin_lock_irqsave(&info->slock, flags);
- written = kfifo_in(&info->port.xmit_fifo, buf, count);
- is_empty = kfifo_is_empty(&info->port.xmit_fifo);
- spin_unlock_irqrestore(&info->slock, flags);
+ scoped_guard(spinlock_irqsave, &info->slock) {
+ written = kfifo_in(&info->port.xmit_fifo, buf, count);
+ is_empty = kfifo_is_empty(&info->port.xmit_fifo);
+ }
if (!is_empty && !tty->flow.stopped)
if (!tty->hw_stopped || mxser_16550A_or_MUST(info))
@@ -920,14 +908,9 @@ static ssize_t mxser_write(struct tty_struct *tty, const u8 *buf, size_t count)
static int mxser_put_char(struct tty_struct *tty, u8 ch)
{
struct mxser_port *info = tty->driver_data;
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&info->slock, flags);
- ret = kfifo_put(&info->port.xmit_fifo, ch);
- spin_unlock_irqrestore(&info->slock, flags);
-
- return ret;
+ guard(spinlock_irqsave)(&info->slock);
+ return kfifo_put(&info->port.xmit_fifo, ch);
}
@@ -968,7 +951,7 @@ static int mxser_get_serial_info(struct tty_struct *tty,
struct tty_port *port = &info->port;
unsigned int closing_wait, close_delay;
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
close_delay = jiffies_to_msecs(info->port.close_delay) / 10;
closing_wait = info->port.closing_wait;
@@ -984,7 +967,7 @@ static int mxser_get_serial_info(struct tty_struct *tty,
ss->close_delay = close_delay;
ss->closing_wait = closing_wait;
ss->custom_divisor = MXSER_CUSTOM_DIVISOR;
- mutex_unlock(&port->mutex);
+
return 0;
}
@@ -994,20 +977,15 @@ static int mxser_set_serial_info(struct tty_struct *tty,
struct mxser_port *info = tty->driver_data;
struct tty_port *port = &info->port;
speed_t baud;
- unsigned long sl_flags;
unsigned int old_speed, close_delay, closing_wait;
- int retval = 0;
if (tty_io_error(tty))
return -EIO;
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
- if (ss->irq != info->board->irq ||
- ss->port != info->ioaddr) {
- mutex_unlock(&port->mutex);
+ if (ss->irq != info->board->irq || ss->port != info->ioaddr)
return -EINVAL;
- }
old_speed = port->flags & ASYNC_SPD_MASK;
@@ -1020,10 +998,9 @@ static int mxser_set_serial_info(struct tty_struct *tty,
if ((ss->baud_base != MXSER_BAUD_BASE) ||
(close_delay != port->close_delay) ||
(closing_wait != port->closing_wait) ||
- ((ss->flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) {
- mutex_unlock(&port->mutex);
+ ((ss->flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK)))
return -EPERM;
- }
+
port->flags = (port->flags & ~ASYNC_USR_MASK) |
(ss->flags & ASYNC_USR_MASK);
} else {
@@ -1039,10 +1016,9 @@ static int mxser_set_serial_info(struct tty_struct *tty,
(ss->baud_base != MXSER_BAUD_BASE ||
ss->custom_divisor !=
MXSER_CUSTOM_DIVISOR)) {
- if (ss->custom_divisor == 0) {
- mutex_unlock(&port->mutex);
+ if (ss->custom_divisor == 0)
return -EINVAL;
- }
+
baud = ss->baud_base / ss->custom_divisor;
tty_encode_baud_rate(tty, baud, baud);
}
@@ -1054,16 +1030,17 @@ static int mxser_set_serial_info(struct tty_struct *tty,
if (tty_port_initialized(port)) {
if (old_speed != (port->flags & ASYNC_SPD_MASK)) {
- spin_lock_irqsave(&info->slock, sl_flags);
+ guard(spinlock_irqsave)(&info->slock);
mxser_change_speed(tty, NULL);
- spin_unlock_irqrestore(&info->slock, sl_flags);
}
- } else {
- retval = mxser_activate(port, tty);
- if (retval == 0)
- tty_port_set_initialized(port, true);
+
+ return 0;
}
- mutex_unlock(&port->mutex);
+
+ int retval = mxser_activate(port, tty);
+ if (retval == 0)
+ tty_port_set_initialized(port, true);
+
return retval;
}
@@ -1080,13 +1057,11 @@ static int mxser_set_serial_info(struct tty_struct *tty,
static int mxser_get_lsr_info(struct mxser_port *info,
unsigned int __user *value)
{
- unsigned char status;
unsigned int result;
- unsigned long flags;
+ u8 status;
- spin_lock_irqsave(&info->slock, flags);
- status = inb(info->ioaddr + UART_LSR);
- spin_unlock_irqrestore(&info->slock, flags);
+ scoped_guard(spinlock_irqsave, &info->slock)
+ status = inb(info->ioaddr + UART_LSR);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
return put_user(result, value);
}
@@ -1095,16 +1070,15 @@ static int mxser_tiocmget(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
unsigned char control;
- unsigned long flags;
u8 msr;
if (tty_io_error(tty))
return -EIO;
- spin_lock_irqsave(&info->slock, flags);
- control = info->MCR;
- msr = mxser_check_modem_status(tty, info);
- spin_unlock_irqrestore(&info->slock, flags);
+ scoped_guard(spinlock_irqsave, &info->slock) {
+ control = info->MCR;
+ msr = mxser_check_modem_status(tty, info);
+ }
return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
@@ -1118,12 +1092,11 @@ static int mxser_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct mxser_port *info = tty->driver_data;
- unsigned long flags;
if (tty_io_error(tty))
return -EIO;
- spin_lock_irqsave(&info->slock, flags);
+ guard(spinlock_irqsave)(&info->slock);
if (set & TIOCM_RTS)
info->MCR |= UART_MCR_RTS;
@@ -1136,7 +1109,7 @@ static int mxser_tiocmset(struct tty_struct *tty,
info->MCR &= ~UART_MCR_DTR;
outb(info->MCR, info->ioaddr + UART_MCR);
- spin_unlock_irqrestore(&info->slock, flags);
+
return 0;
}
@@ -1144,12 +1117,11 @@ static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg,
struct async_icount *cprev)
{
struct async_icount cnow;
- unsigned long flags;
int ret;
- spin_lock_irqsave(&info->slock, flags);
- cnow = info->icount; /* atomic copy */
- spin_unlock_irqrestore(&info->slock, flags);
+ /* atomic copy */
+ scoped_guard(spinlock_irqsave, &info->slock)
+ cnow = info->icount;
ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
@@ -1179,19 +1151,17 @@ static int mxser_ioctl_op_mode(struct mxser_port *port, int index, bool set,
if (opmode & ~OP_MODE_MASK)
return -EINVAL;
- spin_lock_irq(&port->slock);
+ guard(spinlock_irq)(&port->slock);
val = inb(port->opmode_ioaddr);
val &= ~(OP_MODE_MASK << shiftbit);
val |= (opmode << shiftbit);
outb(val, port->opmode_ioaddr);
- spin_unlock_irq(&port->slock);
return 0;
}
- spin_lock_irq(&port->slock);
- opmode = inb(port->opmode_ioaddr) >> shiftbit;
- spin_unlock_irq(&port->slock);
+ scoped_guard(spinlock_irq, &port->slock)
+ opmode = inb(port->opmode_ioaddr) >> shiftbit;
return put_user(opmode & OP_MODE_MASK, u_opmode);
}
@@ -1201,7 +1171,6 @@ static int mxser_ioctl(struct tty_struct *tty,
{
struct mxser_port *info = tty->driver_data;
struct async_icount cnow;
- unsigned long flags;
void __user *argp = (void __user *)arg;
if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE)
@@ -1221,9 +1190,9 @@ static int mxser_ioctl(struct tty_struct *tty,
* Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
- spin_lock_irqsave(&info->slock, flags);
- cnow = info->icount; /* note the counters on entry */
- spin_unlock_irqrestore(&info->slock, flags);
+ /* note the counters on entry */
+ scoped_guard(spinlock_irqsave, &info->slock)
+ cnow = info->icount;
return wait_event_interruptible(info->port.delta_msr_wait,
mxser_cflags_changed(info, arg, &cnow));
@@ -1246,11 +1215,9 @@ static int mxser_get_icount(struct tty_struct *tty,
{
struct mxser_port *info = tty->driver_data;
struct async_icount cnow;
- unsigned long flags;
- spin_lock_irqsave(&info->slock, flags);
- cnow = info->icount;
- spin_unlock_irqrestore(&info->slock, flags);
+ scoped_guard(spinlock_irqsave, &info->slock)
+ cnow = info->icount;
icount->frame = cnow.frame;
icount->brk = cnow.brk;
@@ -1328,34 +1295,28 @@ static void mxser_unthrottle(struct tty_struct *tty)
static void mxser_stop(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
- unsigned long flags;
- spin_lock_irqsave(&info->slock, flags);
+ guard(spinlock_irqsave)(&info->slock);
if (info->IER & UART_IER_THRI)
__mxser_stop_tx(info);
- spin_unlock_irqrestore(&info->slock, flags);
}
static void mxser_start(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
- unsigned long flags;
- spin_lock_irqsave(&info->slock, flags);
+ guard(spinlock_irqsave)(&info->slock);
if (!kfifo_is_empty(&info->port.xmit_fifo))
__mxser_start_tx(info);
- spin_unlock_irqrestore(&info->slock, flags);
}
static void mxser_set_termios(struct tty_struct *tty,
const struct ktermios *old_termios)
{
struct mxser_port *info = tty->driver_data;
- unsigned long flags;
- spin_lock_irqsave(&info->slock, flags);
- mxser_change_speed(tty, old_termios);
- spin_unlock_irqrestore(&info->slock, flags);
+ scoped_guard(spinlock_irqsave, &info->slock)
+ mxser_change_speed(tty, old_termios);
if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
tty->hw_stopped = false;
@@ -1367,9 +1328,8 @@ static void mxser_set_termios(struct tty_struct *tty,
tty->flow.stopped = 0;
if (info->board->must_hwid) {
- spin_lock_irqsave(&info->slock, flags);
+ guard(spinlock_irqsave)(&info->slock);
mxser_must_set_rx_sw_flow_control(info->ioaddr, false);
- spin_unlock_irqrestore(&info->slock, flags);
}
mxser_start(tty);
@@ -1378,14 +1338,8 @@ static void mxser_set_termios(struct tty_struct *tty,
static bool mxser_tx_empty(struct mxser_port *info)
{
- unsigned long flags;
- u8 lsr;
-
- spin_lock_irqsave(&info->slock, flags);
- lsr = inb(info->ioaddr + UART_LSR);
- spin_unlock_irqrestore(&info->slock, flags);
-
- return !(lsr & UART_LSR_TEMT);
+ guard(spinlock_irqsave)(&info->slock);
+ return !(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT);
}
/*
@@ -1459,17 +1413,15 @@ static void mxser_hangup(struct tty_struct *tty)
static int mxser_rs_break(struct tty_struct *tty, int break_state)
{
struct mxser_port *info = tty->driver_data;
- unsigned long flags;
u8 lcr;
- spin_lock_irqsave(&info->slock, flags);
+ guard(spinlock_irqsave)(&info->slock);
lcr = inb(info->ioaddr + UART_LCR);
if (break_state == -1)
lcr |= UART_LCR_SBC;
else
lcr &= ~UART_LCR_SBC;
outb(lcr, info->ioaddr + UART_LCR);
- spin_unlock_irqrestore(&info->slock, flags);
return 0;
}
@@ -1600,54 +1552,50 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port
static bool mxser_port_isr(struct mxser_port *port)
{
- struct tty_struct *tty;
u8 iir, status;
- bool error = false;
iir = inb(port->ioaddr + UART_IIR);
if (iir & UART_IIR_NO_INT)
return true;
iir &= MOXA_MUST_IIR_MASK;
- tty = tty_port_tty_get(&port->port);
- if (!tty) {
- status = inb(port->ioaddr + UART_LSR);
- outb(port->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
- port->ioaddr + UART_FCR);
- inb(port->ioaddr + UART_MSR);
- error = true;
- goto put_tty;
+ scoped_guard(tty_port_tty, &port->port) {
+ struct tty_struct *tty = scoped_tty();
+
+ status = inb(port->ioaddr + UART_LSR);
+
+ if (port->board->must_hwid) {
+ if (iir == MOXA_MUST_IIR_GDA ||
+ iir == MOXA_MUST_IIR_RDA ||
+ iir == MOXA_MUST_IIR_RTO ||
+ iir == MOXA_MUST_IIR_LSR)
+ status = mxser_receive_chars(tty, port, status);
+ } else {
+ status &= port->read_status_mask;
+ if (status & UART_LSR_DR)
+ status = mxser_receive_chars(tty, port, status);
+ }
+
+ mxser_check_modem_status(tty, port);
+
+ if (port->board->must_hwid) {
+ if (iir == 0x02 && (status & UART_LSR_THRE))
+ mxser_transmit_chars(tty, port);
+ } else {
+ if (status & UART_LSR_THRE)
+ mxser_transmit_chars(tty, port);
+ }
+
+ return false;
}
status = inb(port->ioaddr + UART_LSR);
+ outb(port->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+ port->ioaddr + UART_FCR);
+ inb(port->ioaddr + UART_MSR);
- if (port->board->must_hwid) {
- if (iir == MOXA_MUST_IIR_GDA ||
- iir == MOXA_MUST_IIR_RDA ||
- iir == MOXA_MUST_IIR_RTO ||
- iir == MOXA_MUST_IIR_LSR)
- status = mxser_receive_chars(tty, port, status);
- } else {
- status &= port->read_status_mask;
- if (status & UART_LSR_DR)
- status = mxser_receive_chars(tty, port, status);
- }
-
- mxser_check_modem_status(tty, port);
-
- if (port->board->must_hwid) {
- if (iir == 0x02 && (status & UART_LSR_THRE))
- mxser_transmit_chars(tty, port);
- } else {
- if (status & UART_LSR_THRE)
- mxser_transmit_chars(tty, port);
- }
-
-put_tty:
- tty_kref_put(tty);
-
- return error;
+ return true;
}
/*
@@ -1676,12 +1624,11 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
port = &brd->ports[i];
int_cnt = 0;
- spin_lock(&port->slock);
+ guard(spinlock)(&port->slock);
do {
if (mxser_port_isr(port))
break;
} while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
- spin_unlock(&port->slock);
}
}
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 7fc5354..553d8c7 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -461,6 +461,7 @@ static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg);
static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr);
static void gsmld_write_trigger(struct gsm_mux *gsm);
static void gsmld_write_task(struct work_struct *work);
+static int gsm_modem_send_initial_msc(struct gsm_dlci *dlci);
/**
* gsm_fcs_add - update FCS
@@ -2174,7 +2175,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
pr_debug("DLCI %d goes open.\n", dlci->addr);
/* Send current modem state */
if (dlci->addr) {
- gsm_modem_update(dlci, 0);
+ gsm_modem_send_initial_msc(dlci);
} else {
/* Start keep-alive control */
gsm->ka_num = 0;
@@ -4162,6 +4163,28 @@ 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
+ *
+ * Send an initial MSC message after DLCI open to set the initial
+ * modem status lines. This is only done for basic mode.
+ * Does not wait for a response as we cannot block the input queue
+ * processing.
+ */
+static int gsm_modem_send_initial_msc(struct gsm_dlci *dlci)
+{
+ u8 modembits[2];
+
+ if (dlci->adaption != 1 || dlci->gsm->encoding != GSM_BASIC_OPT)
+ return 0;
+
+ modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */
+ modembits[1] = (gsm_encode_modem(dlci) << 1) | EA;
+ return gsm_control_command(dlci->gsm, CMD_MSC, (const u8 *)&modembits, 2);
+}
+
+/**
* gsm_modem_update - send modem status line state
* @dlci: channel
* @brk: break signal
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index d16c207..b33e708 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -399,15 +399,12 @@ static int serdev_drv_probe(struct device *dev)
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
int ret;
- ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON);
+ ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON |
+ PD_FLAG_DETACH_POWER_OFF);
if (ret)
return ret;
- ret = sdrv->probe(to_serdev_device(dev));
- if (ret)
- dev_pm_domain_detach(dev, true);
-
- return ret;
+ return sdrv->probe(to_serdev_device(dev));
}
static void serdev_drv_remove(struct device *dev)
@@ -415,8 +412,6 @@ static void serdev_drv_remove(struct device *dev)
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
if (sdrv->remove)
sdrv->remove(to_serdev_device(dev));
-
- dev_pm_domain_detach(dev, true);
}
static const struct bus_type serdev_bus_type = {
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index cfe6ba2..58e64c4 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -186,6 +186,11 @@ static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up,
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
+void serial8250_rpm_get(struct uart_8250_port *p);
+void serial8250_rpm_put(struct uart_8250_port *p);
+DEFINE_GUARD(serial8250_rpm, struct uart_8250_port *,
+ serial8250_rpm_get(_T), serial8250_rpm_put(_T));
+
static inline u32 serial_dl_read(struct uart_8250_port *up)
{
return up->dl_read(up);
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index feb920c..bfa421a 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -72,7 +72,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
struct list_head *l, *end = NULL;
int pass_counter = 0, handled = 0;
- spin_lock(&i->lock);
+ guard(spinlock)(&i->lock);
l = i->head;
do {
@@ -91,8 +91,6 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
break;
} while (l != end);
- spin_unlock(&i->lock);
-
return IRQ_RETVAL(handled);
}
@@ -132,22 +130,19 @@ static struct irq_info *serial_get_or_create_irq_info(const struct uart_8250_por
{
struct irq_info *i;
- mutex_lock(&hash_mutex);
+ guard(mutex)(&hash_mutex);
hash_for_each_possible(irq_lists, i, node, up->port.irq)
if (i->irq == up->port.irq)
- goto unlock;
+ return i;
i = kzalloc(sizeof(*i), GFP_KERNEL);
- if (i == NULL) {
- i = ERR_PTR(-ENOMEM);
- goto unlock;
- }
+ if (i == NULL)
+ return ERR_PTR(-ENOMEM);
+
spin_lock_init(&i->lock);
i->irq = up->port.irq;
hash_add(irq_lists, &i->node, i->irq);
-unlock:
- mutex_unlock(&hash_mutex);
return i;
}
@@ -161,23 +156,21 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
if (IS_ERR(i))
return PTR_ERR(i);
- spin_lock_irq(&i->lock);
+ scoped_guard(spinlock_irq, &i->lock) {
+ if (i->head) {
+ list_add(&up->list, i->head);
- if (i->head) {
- list_add(&up->list, i->head);
- spin_unlock_irq(&i->lock);
+ return 0;
+ }
- ret = 0;
- } else {
INIT_LIST_HEAD(&up->list);
i->head = &up->list;
- spin_unlock_irq(&i->lock);
- ret = request_irq(up->port.irq, serial8250_interrupt,
- up->port.irqflags, up->port.name, i);
- if (ret < 0)
- serial_do_unlink(i, up);
}
+ ret = request_irq(up->port.irq, serial8250_interrupt, up->port.irqflags, up->port.name, i);
+ if (ret < 0)
+ serial_do_unlink(i, up);
+
return ret;
}
@@ -185,20 +178,22 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
{
struct irq_info *i;
- mutex_lock(&hash_mutex);
+ guard(mutex)(&hash_mutex);
hash_for_each_possible(irq_lists, i, node, up->port.irq)
- if (i->irq == up->port.irq)
- break;
+ if (i->irq == up->port.irq) {
+ if (WARN_ON(i->head == NULL))
+ return;
- BUG_ON(i == NULL);
- BUG_ON(i->head == NULL);
+ if (list_empty(i->head))
+ free_irq(up->port.irq, i);
- if (list_empty(i->head))
- free_irq(up->port.irq, i);
+ serial_do_unlink(i, up);
- serial_do_unlink(i, up);
- mutex_unlock(&hash_mutex);
+ return;
+ }
+
+ WARN_ON(1);
}
/*
@@ -307,7 +302,7 @@ static void univ8250_release_irq(struct uart_8250_port *up)
serial_unlink_irq_chain(up);
}
-const struct uart_ops *univ8250_port_base_ops = NULL;
+const struct uart_ops *univ8250_port_base_ops;
struct uart_ops univ8250_port_ops;
static const struct uart_8250_ops univ8250_driver_ops = {
@@ -670,16 +665,12 @@ static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_
static void serial_8250_overrun_backoff_work(struct work_struct *work)
{
- struct uart_8250_port *up =
- container_of(to_delayed_work(work), struct uart_8250_port,
- overrun_backoff);
- struct uart_port *port = &up->port;
- unsigned long flags;
+ struct uart_8250_port *up = container_of(to_delayed_work(work), struct uart_8250_port,
+ overrun_backoff);
- uart_port_lock_irqsave(port, &flags);
+ guard(uart_port_lock_irqsave)(&up->port);
up->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
- uart_port_unlock_irqrestore(port, flags);
}
/**
@@ -698,12 +689,12 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
int serial8250_register_8250_port(const struct uart_8250_port *up)
{
struct uart_8250_port *uart;
- int ret = -ENOSPC;
+ int ret;
if (up->port.uartclk == 0)
return -EINVAL;
- mutex_lock(&serial_mutex);
+ guard(mutex)(&serial_mutex);
uart = serial8250_find_match_or_unused(&up->port);
if (!uart) {
@@ -713,15 +704,13 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
*/
uart = serial8250_setup_port(nr_uarts);
if (!uart)
- goto unlock;
+ return -ENOSPC;
nr_uarts++;
}
/* Check if it is CIR already. We check this below again, see there why. */
- if (uart->port.type == PORT_8250_CIR) {
- ret = -ENODEV;
- goto unlock;
- }
+ if (uart->port.type == PORT_8250_CIR)
+ return -ENODEV;
if (uart->port.dev)
uart_remove_one_port(&serial8250_reg, &uart->port);
@@ -855,14 +844,10 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
uart->overrun_backoff_time_ms = 0;
}
-unlock:
- mutex_unlock(&serial_mutex);
-
return ret;
err:
uart->port.dev = NULL;
- mutex_unlock(&serial_mutex);
return ret;
}
EXPORT_SYMBOL(serial8250_register_8250_port);
@@ -878,14 +863,11 @@ void serial8250_unregister_port(int line)
{
struct uart_8250_port *uart = &serial8250_ports[line];
- mutex_lock(&serial_mutex);
+ guard(mutex)(&serial_mutex);
if (uart->em485) {
- unsigned long flags;
-
- uart_port_lock_irqsave(&uart->port, &flags);
+ guard(uart_port_lock_irqsave)(&uart->port);
serial8250_em485_destroy(uart);
- uart_port_unlock_irqrestore(&uart->port, flags);
}
uart_remove_one_port(&serial8250_reg, &uart->port);
@@ -901,7 +883,6 @@ void serial8250_unregister_port(int line)
} else {
uart->port.dev = NULL;
}
- mutex_unlock(&serial_mutex);
}
EXPORT_SYMBOL(serial8250_unregister_port);
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 6707f55..9e49ef4 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -27,6 +27,8 @@
#include <linux/pm_wakeirq.h>
#include <linux/dma-mapping.h>
#include <linux/sys_soc.h>
+#include <linux/reboot.h>
+#include <linux/pinctrl/consumer.h>
#include "8250.h"
@@ -145,6 +147,9 @@ struct omap8250_priv {
spinlock_t rx_dma_lock;
bool rx_dma_broken;
bool throttled;
+
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pinctrl_wakeup;
};
struct omap8250_dma_params {
@@ -369,18 +374,12 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
serial8250_em485_stop_tx(up, true);
}
-/*
- * OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have
- * some differences in how we want to handle flow control.
- */
-static void omap_8250_set_termios(struct uart_port *port,
- struct ktermios *termios,
- const struct ktermios *old)
+static void omap_8250_set_termios_atomic(struct uart_port *port, struct ktermios *termios,
+ const struct ktermios *old, unsigned int baud)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = port->private_data;
- unsigned char cval = 0;
- unsigned int baud;
+ u8 cval;
cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag));
@@ -393,20 +392,14 @@ static void omap_8250_set_termios(struct uart_port *port,
if (termios->c_cflag & CMSPAR)
cval |= UART_LCR_SPAR;
- /*
- * Ask the core to calculate the divisor for us.
- */
- baud = uart_get_baud_rate(port, termios, old,
- port->uartclk / 16 / UART_DIV_MAX,
- port->uartclk / 13);
omap_8250_get_divisor(port, baud, priv);
/*
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
- pm_runtime_get_sync(port->dev);
- uart_port_lock_irq(port);
+ guard(serial8250_rpm)(up);
+ guard(uart_port_lock_irq)(port);
/*
* Update the per-port timeout.
@@ -514,10 +507,27 @@ static void omap_8250_set_termios(struct uart_port *port,
}
}
omap8250_restore_regs(up);
+}
- uart_port_unlock_irq(&up->port);
- pm_runtime_mark_last_busy(port->dev);
- pm_runtime_put_autosuspend(port->dev);
+/*
+ * OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have
+ * some differences in how we want to handle flow control.
+ */
+static void omap_8250_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ const struct ktermios *old)
+{
+ struct omap8250_priv *priv = port->private_data;
+ unsigned int baud;
+
+ /*
+ * Ask the core to calculate the divisor for us.
+ */
+ baud = uart_get_baud_rate(port, termios, old,
+ port->uartclk / 16 / UART_DIV_MAX,
+ port->uartclk / 13);
+
+ omap_8250_set_termios_atomic(port, termios, old, baud);
/* calculate wakeup latency constraint */
priv->calc_latency = USEC_PER_SEC * 64 * 8 / baud;
@@ -537,10 +547,9 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state,
struct uart_8250_port *up = up_to_u8250p(port);
u8 efr;
- pm_runtime_get_sync(port->dev);
-
+ guard(serial8250_rpm)(up);
/* Synchronize UART_IER access against the console. */
- uart_port_lock_irq(port);
+ guard(uart_port_lock_irq)(port);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
efr = serial_in(up, UART_EFR);
@@ -551,11 +560,6 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state,
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, efr);
serial_out(up, UART_LCR, 0);
-
- uart_port_unlock_irq(port);
-
- pm_runtime_mark_last_busy(port->dev);
- pm_runtime_put_autosuspend(port->dev);
}
static void omap_serial_fill_features_erratas(struct uart_8250_port *up,
@@ -727,7 +731,11 @@ static int omap_8250_startup(struct uart_port *port)
return ret;
}
- pm_runtime_get_sync(port->dev);
+#ifdef CONFIG_PM
+ up->capabilities |= UART_CAP_RPM;
+#endif
+
+ guard(serial8250_rpm)(up);
serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
@@ -750,14 +758,10 @@ static int omap_8250_startup(struct uart_port *port)
}
/* Synchronize UART_IER access against the console. */
- uart_port_lock_irq(port);
- up->ier = UART_IER_RLSI | UART_IER_RDI;
- serial_out(up, UART_IER, up->ier);
- uart_port_unlock_irq(port);
-
-#ifdef CONFIG_PM
- up->capabilities |= UART_CAP_RPM;
-#endif
+ scoped_guard(uart_port_lock_irq, port) {
+ up->ier = UART_IER_RLSI | UART_IER_RDI;
+ serial_out(up, UART_IER, up->ier);
+ }
/* Enable module level wake up */
priv->wer = OMAP_UART_WER_MOD_WKUP;
@@ -766,15 +770,12 @@ static int omap_8250_startup(struct uart_port *port)
serial_out(up, UART_OMAP_WER, priv->wer);
if (up->dma && !(priv->habit & UART_HAS_EFR2)) {
- uart_port_lock_irq(port);
+ guard(uart_port_lock_irq)(port);
up->dma->rx_dma(up);
- uart_port_unlock_irq(port);
}
enable_irq(port->irq);
- pm_runtime_mark_last_busy(port->dev);
- pm_runtime_put_autosuspend(port->dev);
return 0;
}
@@ -783,7 +784,7 @@ static void omap_8250_shutdown(struct uart_port *port)
struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = port->private_data;
- pm_runtime_get_sync(port->dev);
+ guard(serial8250_rpm)(up);
flush_work(&priv->qos_work);
if (up->dma)
@@ -794,10 +795,11 @@ static void omap_8250_shutdown(struct uart_port *port)
serial_out(up, UART_OMAP_EFR2, 0x0);
/* Synchronize UART_IER access against the console. */
- uart_port_lock_irq(port);
- up->ier = 0;
- serial_out(up, UART_IER, 0);
- uart_port_unlock_irq(port);
+ scoped_guard(uart_port_lock_irq, port) {
+ up->ier = 0;
+ serial_out(up, UART_IER, 0);
+ }
+
disable_irq_nosync(port->irq);
dev_pm_clear_wake_irq(port->dev);
@@ -810,46 +812,33 @@ static void omap_8250_shutdown(struct uart_port *port)
if (up->lcr & UART_LCR_SBC)
serial_out(up, UART_LCR, up->lcr & ~UART_LCR_SBC);
serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-
- pm_runtime_mark_last_busy(port->dev);
- pm_runtime_put_autosuspend(port->dev);
}
static void omap_8250_throttle(struct uart_port *port)
{
struct omap8250_priv *priv = port->private_data;
- unsigned long flags;
- pm_runtime_get_sync(port->dev);
+ guard(serial8250_rpm)(up_to_u8250p(port));
+ guard(uart_port_lock_irqsave)(port);
- uart_port_lock_irqsave(port, &flags);
port->ops->stop_rx(port);
priv->throttled = true;
- uart_port_unlock_irqrestore(port, flags);
-
- pm_runtime_mark_last_busy(port->dev);
- pm_runtime_put_autosuspend(port->dev);
}
static void omap_8250_unthrottle(struct uart_port *port)
{
struct omap8250_priv *priv = port->private_data;
struct uart_8250_port *up = up_to_u8250p(port);
- unsigned long flags;
- pm_runtime_get_sync(port->dev);
-
+ guard(serial8250_rpm)(up);
/* Synchronize UART_IER access against the console. */
- uart_port_lock_irqsave(port, &flags);
+ guard(uart_port_lock_irqsave)(port);
+
priv->throttled = false;
if (up->dma)
up->dma->rx_dma(up);
up->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
- uart_port_unlock_irqrestore(port, flags);
-
- pm_runtime_mark_last_busy(port->dev);
- pm_runtime_put_autosuspend(port->dev);
}
static int omap8250_rs485_config(struct uart_port *port,
@@ -987,30 +976,26 @@ static void __dma_rx_complete(void *param)
struct omap8250_priv *priv = p->port.private_data;
struct uart_8250_dma *dma = p->dma;
struct dma_tx_state state;
- unsigned long flags;
/* Synchronize UART_IER access against the console. */
- uart_port_lock_irqsave(&p->port, &flags);
+ guard(uart_port_lock_irqsave)(&p->port);
/*
* If the tx status is not DMA_COMPLETE, then this is a delayed
* completion callback. A previous RX timeout flush would have
* already pushed the data, so exit.
*/
- if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) !=
- DMA_COMPLETE) {
- uart_port_unlock_irqrestore(&p->port, flags);
+ if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) != DMA_COMPLETE)
return;
- }
- __dma_rx_do_complete(p);
- if (!priv->throttled) {
- p->ier |= UART_IER_RLSI | UART_IER_RDI;
- serial_out(p, UART_IER, p->ier);
- if (!(priv->habit & UART_HAS_EFR2))
- omap_8250_rx_dma(p);
- }
- uart_port_unlock_irqrestore(&p->port, flags);
+ __dma_rx_do_complete(p);
+ if (priv->throttled)
+ return;
+
+ p->ier |= UART_IER_RLSI | UART_IER_RDI;
+ serial_out(p, UART_IER, p->ier);
+ if (!(priv->habit & UART_HAS_EFR2))
+ omap_8250_rx_dma(p);
}
static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
@@ -1108,14 +1093,13 @@ static void omap_8250_dma_tx_complete(void *param)
struct uart_8250_port *p = param;
struct uart_8250_dma *dma = p->dma;
struct tty_port *tport = &p->port.state->port;
- unsigned long flags;
bool en_thri = false;
struct omap8250_priv *priv = p->port.private_data;
dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
- uart_port_lock_irqsave(&p->port, &flags);
+ guard(uart_port_lock_irqsave)(&p->port);
dma->tx_running = 0;
@@ -1143,8 +1127,6 @@ static void omap_8250_dma_tx_complete(void *param)
dma->tx_err = 1;
serial8250_set_THRI(p);
}
-
- uart_port_unlock_irqrestore(&p->port, flags);
}
static int omap_8250_tx_dma(struct uart_8250_port *p)
@@ -1372,6 +1354,18 @@ static int omap8250_no_handle_irq(struct uart_port *port)
return 0;
}
+static int omap8250_select_wakeup_pinctrl(struct device *dev,
+ struct omap8250_priv *priv)
+{
+ if (IS_ERR_OR_NULL(priv->pinctrl_wakeup))
+ return 0;
+
+ if (!device_may_wakeup(dev))
+ return 0;
+
+ return pinctrl_select_state(priv->pinctrl, priv->pinctrl_wakeup);
+}
+
static struct omap8250_dma_params am654_dma = {
.rx_size = SZ_2K,
.rx_trigger = 1,
@@ -1596,6 +1590,11 @@ static int omap8250_probe(struct platform_device *pdev)
priv->line = ret;
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
+
+ priv->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (!IS_ERR_OR_NULL(priv->pinctrl))
+ priv->pinctrl_wakeup = pinctrl_lookup_state(priv->pinctrl, "wakeup");
+
return 0;
err:
pm_runtime_dont_use_autosuspend(&pdev->dev);
@@ -1653,6 +1652,13 @@ static int omap8250_suspend(struct device *dev)
struct uart_8250_port *up = serial8250_get_port(priv->line);
int err = 0;
+ err = omap8250_select_wakeup_pinctrl(dev, priv);
+ if (err) {
+ dev_err(dev, "Failed to select wakeup pinctrl, aborting suspend %pe\n",
+ ERR_PTR(err));
+ return err;
+ }
+
serial8250_suspend_port(priv->line);
err = pm_runtime_resume_and_get(dev);
@@ -1674,6 +1680,13 @@ static int omap8250_resume(struct device *dev)
struct uart_8250_port *up = serial8250_get_port(priv->line);
int err;
+ err = pinctrl_select_default_state(dev);
+ if (err) {
+ dev_err(dev, "Failed to select default pinctrl state on resume: %pe\n",
+ ERR_PTR(err));
+ return err;
+ }
+
if (uart_console(&up->port) && console_suspend_enabled) {
err = pm_runtime_force_resume(dev);
if (err)
@@ -1795,15 +1808,13 @@ static int omap8250_runtime_resume(struct device *dev)
up = serial8250_get_port(priv->line);
if (up && omap8250_lost_context(up)) {
- uart_port_lock_irq(&up->port);
+ guard(uart_port_lock_irq)(&up->port);
omap8250_restore_regs(up);
- uart_port_unlock_irq(&up->port);
}
if (up && up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2)) {
- uart_port_lock_irq(&up->port);
+ guard(uart_port_lock_irq)(&up->port);
omap_8250_rx_dma(up);
- uart_port_unlock_irq(&up->port);
}
atomic_set(&priv->active, 1);
diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c
index c0343bf..b279813 100644
--- a/drivers/tty/serial/8250/8250_platform.c
+++ b/drivers/tty/serial/8250/8250_platform.c
@@ -10,6 +10,7 @@
*/
#include <linux/acpi.h>
#include <linux/array_size.h>
+#include <linux/cleanup.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -110,41 +111,44 @@ void __init serial8250_isa_init_ports(void)
static int serial8250_probe_acpi(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct uart_8250_port uart = { };
struct resource *regs;
int ret, line;
+ struct uart_8250_port *uart __free(kfree) = kzalloc(sizeof(*uart), GFP_KERNEL);
+ if (!uart)
+ return -ENOMEM;
+
regs = platform_get_mem_or_io(pdev, 0);
if (!regs)
return dev_err_probe(dev, -EINVAL, "no registers defined\n");
switch (resource_type(regs)) {
case IORESOURCE_IO:
- uart.port.iobase = regs->start;
+ uart->port.iobase = regs->start;
break;
case IORESOURCE_MEM:
- uart.port.mapbase = regs->start;
- uart.port.mapsize = resource_size(regs);
- uart.port.flags = UPF_IOREMAP;
+ uart->port.mapbase = regs->start;
+ uart->port.mapsize = resource_size(regs);
+ uart->port.flags = UPF_IOREMAP;
break;
default:
return -EINVAL;
}
/* default clock frequency */
- uart.port.uartclk = 1843200;
- uart.port.type = PORT_16550A;
- uart.port.dev = &pdev->dev;
- uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+ uart->port.uartclk = 1843200;
+ uart->port.type = PORT_16550A;
+ uart->port.dev = &pdev->dev;
+ uart->port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
- ret = uart_read_and_validate_port_properties(&uart.port);
+ ret = uart_read_and_validate_port_properties(&uart->port);
/* no interrupt -> fall back to polling */
if (ret == -ENXIO)
ret = 0;
if (ret)
return ret;
- line = serial8250_register_8250_port(&uart);
+ line = serial8250_register_8250_port(uart);
if (line < 0)
return line;
@@ -153,43 +157,44 @@ static int serial8250_probe_acpi(struct platform_device *pdev)
static int serial8250_probe_platform(struct platform_device *dev, struct plat_serial8250_port *p)
{
- struct uart_8250_port uart;
int ret, i, irqflag = 0;
- memset(&uart, 0, sizeof(uart));
+ 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;
- uart.port.irq = p->irq;
- uart.port.irqflags = p->irqflags;
- uart.port.uartclk = p->uartclk;
- uart.port.regshift = p->regshift;
- uart.port.iotype = p->iotype;
- uart.port.flags = p->flags;
- uart.port.mapbase = p->mapbase;
- uart.port.mapsize = p->mapsize;
- uart.port.hub6 = p->hub6;
- uart.port.has_sysrq = p->has_sysrq;
- uart.port.private_data = p->private_data;
- uart.port.type = p->type;
- uart.bugs = p->bugs;
- uart.port.serial_in = p->serial_in;
- uart.port.serial_out = p->serial_out;
- uart.dl_read = p->dl_read;
- uart.dl_write = p->dl_write;
- uart.port.handle_irq = p->handle_irq;
- uart.port.handle_break = p->handle_break;
- uart.port.set_termios = p->set_termios;
- uart.port.set_ldisc = p->set_ldisc;
- uart.port.get_mctrl = p->get_mctrl;
- uart.port.pm = p->pm;
- uart.port.dev = &dev->dev;
- uart.port.irqflags |= irqflag;
- ret = serial8250_register_8250_port(&uart);
+ uart->port.iobase = p->iobase;
+ uart->port.membase = p->membase;
+ uart->port.irq = p->irq;
+ uart->port.irqflags = p->irqflags;
+ uart->port.uartclk = p->uartclk;
+ uart->port.regshift = p->regshift;
+ uart->port.iotype = p->iotype;
+ uart->port.flags = p->flags;
+ uart->port.mapbase = p->mapbase;
+ uart->port.mapsize = p->mapsize;
+ uart->port.hub6 = p->hub6;
+ uart->port.has_sysrq = p->has_sysrq;
+ uart->port.private_data = p->private_data;
+ uart->port.type = p->type;
+ uart->bugs = p->bugs;
+ uart->port.serial_in = p->serial_in;
+ uart->port.serial_out = p->serial_out;
+ uart->dl_read = p->dl_read;
+ uart->dl_write = p->dl_write;
+ uart->port.handle_irq = p->handle_irq;
+ uart->port.handle_break = p->handle_break;
+ uart->port.set_termios = p->set_termios;
+ uart->port.set_ldisc = p->set_ldisc;
+ uart->port.get_mctrl = p->get_mctrl;
+ uart->port.pm = p->pm;
+ uart->port.dev = &dev->dev;
+ uart->port.irqflags |= irqflag;
+ ret = serial8250_register_8250_port(uart);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
"(IO%lx MEM%llx IRQ%d): %d\n", i,
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 2da9db9..719faf9 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -508,20 +508,22 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
-static void serial8250_rpm_get(struct uart_8250_port *p)
+void serial8250_rpm_get(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_get_sync(p->port.dev);
}
+EXPORT_SYMBOL_GPL(serial8250_rpm_get);
-static void serial8250_rpm_put(struct uart_8250_port *p)
+void serial8250_rpm_put(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
+EXPORT_SYMBOL_GPL(serial8250_rpm_put);
/**
* serial8250_em485_init() - put uart_8250_port into rs485 emulating
@@ -672,28 +674,27 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
{
unsigned char lcr = 0, efr = 0;
- serial8250_rpm_get(p);
+ guard(serial8250_rpm)(p);
- if (p->capabilities & UART_CAP_SLEEP) {
- /* Synchronize UART_IER access against the console. */
- uart_port_lock_irq(&p->port);
- if (p->capabilities & UART_CAP_EFR) {
- lcr = serial_in(p, UART_LCR);
- efr = serial_in(p, UART_EFR);
- serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(p, UART_EFR, UART_EFR_ECB);
- serial_out(p, UART_LCR, 0);
- }
- serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
- if (p->capabilities & UART_CAP_EFR) {
- serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(p, UART_EFR, efr);
- serial_out(p, UART_LCR, lcr);
- }
- uart_port_unlock_irq(&p->port);
+ if (!(p->capabilities & UART_CAP_SLEEP))
+ return;
+
+ /* Synchronize UART_IER access against the console. */
+ guard(uart_port_lock_irq)(&p->port);
+
+ if (p->capabilities & UART_CAP_EFR) {
+ lcr = serial_in(p, UART_LCR);
+ efr = serial_in(p, UART_EFR);
+ serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
+ serial_out(p, UART_EFR, UART_EFR_ECB);
+ serial_out(p, UART_LCR, 0);
}
-
- serial8250_rpm_put(p);
+ serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
+ if (p->capabilities & UART_CAP_EFR) {
+ serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
+ serial_out(p, UART_EFR, efr);
+ serial_out(p, UART_LCR, lcr);
+ }
}
/* Clear the interrupt registers. */
@@ -1229,9 +1230,8 @@ static void autoconfig_irq(struct uart_8250_port *up)
probe_irq_off(probe_irq_on());
save_mcr = serial8250_in_MCR(up);
/* Synchronize UART_IER access against the console. */
- uart_port_lock_irq(port);
- save_ier = serial_in(up, UART_IER);
- uart_port_unlock_irq(port);
+ scoped_guard(uart_port_lock_irq, port)
+ save_ier = serial_in(up, UART_IER);
serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2);
irqs = probe_irq_on();
@@ -1244,9 +1244,8 @@ static void autoconfig_irq(struct uart_8250_port *up)
UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
}
/* Synchronize UART_IER access against the console. */
- uart_port_lock_irq(port);
- serial_out(up, UART_IER, UART_IER_ALL_INTR);
- uart_port_unlock_irq(port);
+ scoped_guard(uart_port_lock_irq, port)
+ serial_out(up, UART_IER, UART_IER_ALL_INTR);
serial8250_clear_interrupts(port);
serial_out(up, UART_TX, 0xFF);
udelay(20);
@@ -1254,9 +1253,8 @@ static void autoconfig_irq(struct uart_8250_port *up)
serial8250_out_MCR(up, save_mcr);
/* Synchronize UART_IER access against the console. */
- uart_port_lock_irq(port);
- serial_out(up, UART_IER, save_ier);
- uart_port_unlock_irq(port);
+ scoped_guard(uart_port_lock_irq, port)
+ serial_out(up, UART_IER, save_ier);
if (port->flags & UPF_FOURPORT)
outb_p(save_ICP, ICP);
@@ -1271,12 +1269,10 @@ static void serial8250_stop_rx(struct uart_port *port)
/* Port locked to synchronize UART_IER access against the console. */
lockdep_assert_held_once(&port->lock);
- serial8250_rpm_get(up);
+ guard(serial8250_rpm)(up);
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
serial_port_out(port, UART_IER, up->ier);
-
- serial8250_rpm_put(up);
}
/**
@@ -1320,17 +1316,15 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
struct uart_8250_em485 *em485 = container_of(t, struct uart_8250_em485,
stop_tx_timer);
struct uart_8250_port *p = em485->port;
- unsigned long flags;
- serial8250_rpm_get(p);
- uart_port_lock_irqsave(&p->port, &flags);
+ guard(serial8250_rpm)(p);
+ guard(uart_port_lock_irqsave)(&p->port);
+
if (em485->active_timer == &em485->stop_tx_timer) {
p->rs485_stop_tx(p, true);
em485->active_timer = NULL;
em485->tx_stopped = true;
}
- uart_port_unlock_irqrestore(&p->port, flags);
- serial8250_rpm_put(p);
return HRTIMER_NORESTART;
}
@@ -1405,7 +1399,7 @@ static void serial8250_stop_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- serial8250_rpm_get(up);
+ guard(serial8250_rpm)(up);
__stop_tx(up);
/*
@@ -1415,7 +1409,6 @@ static void serial8250_stop_tx(struct uart_port *port)
up->acr |= UART_ACR_TXDIS;
serial_icr_write(up, UART_ACR, up->acr);
}
- serial8250_rpm_put(up);
}
static inline void __start_tx(struct uart_port *port)
@@ -1510,14 +1503,13 @@ static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t)
struct uart_8250_em485 *em485 = container_of(t, struct uart_8250_em485,
start_tx_timer);
struct uart_8250_port *p = em485->port;
- unsigned long flags;
- uart_port_lock_irqsave(&p->port, &flags);
+ guard(uart_port_lock_irqsave)(&p->port);
+
if (em485->active_timer == &em485->start_tx_timer) {
__start_tx(&p->port);
em485->active_timer = NULL;
}
- uart_port_unlock_irqrestore(&p->port, flags);
return HRTIMER_NORESTART;
}
@@ -1585,9 +1577,8 @@ static void serial8250_enable_ms(struct uart_port *port)
up->ier |= UART_IER_MSI;
- serial8250_rpm_get(up);
+ guard(serial8250_rpm)(up);
serial_port_out(port, UART_IER, up->ier);
- serial8250_rpm_put(up);
}
void serial8250_read_char(struct uart_8250_port *up, u16 lsr)
@@ -1848,15 +1839,11 @@ static int serial8250_default_handle_irq(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int iir;
- int ret;
- serial8250_rpm_get(up);
+ guard(serial8250_rpm)(up);
iir = serial_port_in(port, UART_IIR);
- ret = serial8250_handle_irq(port, iir);
-
- serial8250_rpm_put(up);
- return ret;
+ return serial8250_handle_irq(port, iir);
}
/*
@@ -1867,16 +1854,14 @@ static int serial8250_default_handle_irq(struct uart_port *port)
*/
static int serial8250_tx_threshold_handle_irq(struct uart_port *port)
{
- unsigned long flags;
unsigned int iir = serial_port_in(port, UART_IIR);
/* TX Threshold IRQ triggered so load up FIFO */
if ((iir & UART_IIR_ID) == UART_IIR_THRI) {
struct uart_8250_port *up = up_to_u8250p(port);
- uart_port_lock_irqsave(port, &flags);
+ guard(uart_port_lock_irqsave)(port);
serial8250_tx_chars(up);
- uart_port_unlock_irqrestore(port, flags);
}
iir = serial_port_in(port, UART_IIR);
@@ -1886,19 +1871,14 @@ static int serial8250_tx_threshold_handle_irq(struct uart_port *port)
static unsigned int serial8250_tx_empty(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- unsigned int result = 0;
- unsigned long flags;
- serial8250_rpm_get(up);
+ guard(serial8250_rpm)(up);
+ guard(uart_port_lock_irqsave)(port);
- uart_port_lock_irqsave(port, &flags);
if (!serial8250_tx_dma_running(up) && uart_lsr_tx_empty(serial_lsr_in(up)))
- result = TIOCSER_TEMT;
- uart_port_unlock_irqrestore(port, flags);
+ return TIOCSER_TEMT;
- serial8250_rpm_put(up);
-
- return result;
+ return 0;
}
unsigned int serial8250_do_get_mctrl(struct uart_port *port)
@@ -1907,9 +1887,8 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port)
unsigned int status;
unsigned int val;
- serial8250_rpm_get(up);
- status = serial8250_modem_status(up);
- serial8250_rpm_put(up);
+ scoped_guard(serial8250_rpm, up)
+ status = serial8250_modem_status(up);
val = serial8250_MSR_to_TIOCM(status);
if (up->gpios)
@@ -1953,17 +1932,15 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void serial8250_break_ctl(struct uart_port *port, int break_state)
{
struct uart_8250_port *up = up_to_u8250p(port);
- unsigned long flags;
- serial8250_rpm_get(up);
- uart_port_lock_irqsave(port, &flags);
+ guard(serial8250_rpm)(up);
+ guard(uart_port_lock_irqsave)(port);
+
if (break_state == -1)
up->lcr |= UART_LCR_SBC;
else
up->lcr &= ~UART_LCR_SBC;
serial_port_out(port, UART_LCR, up->lcr);
- uart_port_unlock_irqrestore(port, flags);
- serial8250_rpm_put(up);
}
/* Returns true if @bits were set, false on timeout */
@@ -2023,22 +2000,15 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
static int serial8250_get_poll_char(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- int status;
u16 lsr;
- serial8250_rpm_get(up);
+ guard(serial8250_rpm)(up);
lsr = serial_port_in(port, UART_LSR);
+ if (!(lsr & UART_LSR_DR))
+ return NO_POLL_CHAR;
- if (!(lsr & UART_LSR_DR)) {
- status = NO_POLL_CHAR;
- goto out;
- }
-
- status = serial_port_in(port, UART_RX);
-out:
- serial8250_rpm_put(up);
- return status;
+ return serial_port_in(port, UART_RX);
}
@@ -2056,7 +2026,7 @@ static void serial8250_put_poll_char(struct uart_port *port,
* should allow safe lockless usage here.
*/
- serial8250_rpm_get(up);
+ guard(serial8250_rpm)(up);
/*
* First save the IER then disable the interrupts
*/
@@ -2075,7 +2045,6 @@ static void serial8250_put_poll_char(struct uart_port *port,
*/
wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
serial_port_out(port, UART_IER, ier);
- serial8250_rpm_put(up);
}
#endif /* CONFIG_CONSOLE_POLL */
@@ -2083,16 +2052,15 @@ static void serial8250_put_poll_char(struct uart_port *port,
static void serial8250_startup_special(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- unsigned long flags;
switch (port->type) {
- case PORT_16C950:
+ case PORT_16C950: {
/*
* Wake up and initialize UART
*
* Synchronize UART_IER access against the console.
*/
- uart_port_lock_irqsave(port, &flags);
+ guard(uart_port_lock_irqsave)(port);
up->acr = 0;
serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B);
serial_port_out(port, UART_EFR, UART_EFR_ECB);
@@ -2102,18 +2070,18 @@ static void serial8250_startup_special(struct uart_port *port)
serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B);
serial_port_out(port, UART_EFR, UART_EFR_ECB);
serial_port_out(port, UART_LCR, 0);
- uart_port_unlock_irqrestore(port, flags);
break;
+ }
case PORT_DA830:
/*
* Reset the port
*
* Synchronize UART_IER access against the console.
*/
- uart_port_lock_irqsave(port, &flags);
- serial_port_out(port, UART_IER, 0);
- serial_port_out(port, UART_DA830_PWREMU_MGMT, 0);
- uart_port_unlock_irqrestore(port, flags);
+ scoped_guard(uart_port_lock_irqsave, port) {
+ serial_port_out(port, UART_IER, 0);
+ serial_port_out(port, UART_DA830_PWREMU_MGMT, 0);
+ }
mdelay(10);
/* Enable Tx, Rx and free run mode */
@@ -2171,7 +2139,6 @@ static void serial8250_set_TRG_levels(struct uart_port *port)
static void serial8250_THRE_test(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- unsigned long flags;
bool iir_noint1, iir_noint2;
if (!port->irq)
@@ -2191,19 +2158,17 @@ static void serial8250_THRE_test(struct uart_port *port)
*
* Synchronize UART_IER access against the console.
*/
- uart_port_lock_irqsave(port, &flags);
-
- wait_for_xmitr(up, UART_LSR_THRE);
- serial_port_out_sync(port, UART_IER, UART_IER_THRI);
- udelay(1); /* allow THRE to set */
- iir_noint1 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT;
- serial_port_out(port, UART_IER, 0);
- serial_port_out_sync(port, UART_IER, UART_IER_THRI);
- udelay(1); /* allow a working UART time to re-assert THRE */
- iir_noint2 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT;
- serial_port_out(port, UART_IER, 0);
-
- uart_port_unlock_irqrestore(port, flags);
+ scoped_guard(uart_port_lock_irqsave, port) {
+ wait_for_xmitr(up, UART_LSR_THRE);
+ serial_port_out_sync(port, UART_IER, UART_IER_THRI);
+ udelay(1); /* allow THRE to set */
+ iir_noint1 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT;
+ serial_port_out(port, UART_IER, 0);
+ serial_port_out_sync(port, UART_IER, UART_IER_THRI);
+ udelay(1); /* allow a working UART time to re-assert THRE */
+ iir_noint2 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT;
+ serial_port_out(port, UART_IER, 0);
+ }
if (port->irqflags & IRQF_SHARED)
enable_irq(port->irq);
@@ -2267,14 +2232,11 @@ static void serial8250_iir_txen_test(struct uart_port *port)
static void serial8250_initialize(struct uart_port *port)
{
- unsigned long flags;
-
- uart_port_lock_irqsave(port, &flags);
+ guard(uart_port_lock_irqsave)(port);
serial_port_out(port, UART_LCR, UART_LCR_WLEN8);
serial8250_init_mctrl(port);
serial8250_iir_txen_test(port);
- uart_port_unlock_irqrestore(port, flags);
}
int serial8250_do_startup(struct uart_port *port)
@@ -2293,7 +2255,7 @@ int serial8250_do_startup(struct uart_port *port)
if (port->iotype != up->cur_iotype)
set_io_from_upio(port);
- serial8250_rpm_get(up);
+ guard(serial8250_rpm)(up);
serial8250_startup_special(port);
@@ -2313,8 +2275,7 @@ int serial8250_do_startup(struct uart_port *port)
if (!(port->flags & UPF_BUGGY_UART) &&
(serial_port_in(port, UART_LSR) == 0xff)) {
dev_info_ratelimited(port->dev, "LSR safety check engaged!\n");
- retval = -ENODEV;
- goto out;
+ return -ENODEV;
}
serial8250_set_TRG_levels(port);
@@ -2325,7 +2286,7 @@ int serial8250_do_startup(struct uart_port *port)
retval = up->ops->setup_irq(up);
if (retval)
- goto out;
+ return retval;
serial8250_THRE_test(port);
@@ -2374,10 +2335,8 @@ int serial8250_do_startup(struct uart_port *port)
outb_p(0x80, icp);
inb_p(icp);
}
- retval = 0;
-out:
- serial8250_rpm_put(up);
- return retval;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(serial8250_do_startup);
@@ -2391,7 +2350,6 @@ static int serial8250_startup(struct uart_port *port)
void serial8250_do_shutdown(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- unsigned long flags;
serial8250_rpm_get(up);
/*
@@ -2399,26 +2357,26 @@ void serial8250_do_shutdown(struct uart_port *port)
*
* Synchronize UART_IER access against the console.
*/
- uart_port_lock_irqsave(port, &flags);
- up->ier = 0;
- serial_port_out(port, UART_IER, 0);
- uart_port_unlock_irqrestore(port, flags);
+ scoped_guard(uart_port_lock_irqsave, port) {
+ up->ier = 0;
+ serial_port_out(port, UART_IER, 0);
+ }
synchronize_irq(port->irq);
if (up->dma)
serial8250_release_dma(up);
- uart_port_lock_irqsave(port, &flags);
- if (port->flags & UPF_FOURPORT) {
- /* reset interrupts on the AST Fourport board */
- inb((port->iobase & 0xfe0) | 0x1f);
- port->mctrl |= TIOCM_OUT1;
- } else
- port->mctrl &= ~TIOCM_OUT2;
+ scoped_guard(uart_port_lock_irqsave, port) {
+ if (port->flags & UPF_FOURPORT) {
+ /* reset interrupts on the AST Fourport board */
+ inb((port->iobase & 0xfe0) | 0x1f);
+ port->mctrl |= TIOCM_OUT1;
+ } else
+ port->mctrl &= ~TIOCM_OUT2;
- serial8250_set_mctrl(port, port->mctrl);
- uart_port_unlock_irqrestore(port, flags);
+ serial8250_set_mctrl(port, port->mctrl);
+ }
/*
* Disable break condition and FIFOs
@@ -2610,33 +2568,27 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
{
struct tty_port *tport = &port->state->port;
- struct tty_struct *tty;
- tty = tty_port_tty_get(tport);
- if (!tty) {
- mutex_lock(&tport->mutex);
+ scoped_guard(tty_port_tty, tport) {
+ struct tty_struct *tty = scoped_tty();
+
+ guard(rwsem_write)(&tty->termios_rwsem);
+ guard(mutex)(&tport->mutex);
+
+ if (port->uartclk == uartclk)
+ return;
+
port->uartclk = uartclk;
- mutex_unlock(&tport->mutex);
+
+ if (!tty_port_initialized(tport))
+ return;
+
+ serial8250_do_set_termios(port, &tty->termios, NULL);
+
return;
}
-
- down_write(&tty->termios_rwsem);
- mutex_lock(&tport->mutex);
-
- if (port->uartclk == uartclk)
- goto out_unlock;
-
+ guard(mutex)(&tport->mutex);
port->uartclk = uartclk;
-
- if (!tty_port_initialized(tport))
- goto out_unlock;
-
- serial8250_do_set_termios(port, &tty->termios, NULL);
-
-out_unlock:
- mutex_unlock(&tport->mutex);
- up_write(&tty->termios_rwsem);
- tty_kref_put(tty);
}
EXPORT_SYMBOL_GPL(serial8250_update_uartclk);
@@ -2791,7 +2743,6 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
const struct ktermios *old)
{
struct uart_8250_port *up = up_to_u8250p(port);
- unsigned long flags;
unsigned int baud, quot, frac = 0;
u8 lcr;
@@ -2801,27 +2752,24 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
quot = serial8250_get_divisor(port, baud, &frac);
/*
- * Ok, we're now changing the port state. Do it with
- * interrupts disabled.
+ * Ok, we're now changing the port state. Do it with interrupts disabled.
*
* Synchronize UART_IER access against the console.
*/
- serial8250_rpm_get(up);
- uart_port_lock_irqsave(port, &flags);
+ scoped_guard(serial8250_rpm, up) {
+ guard(uart_port_lock_irqsave)(port);
- up->lcr = lcr;
- serial8250_set_trigger_for_slow_speed(port, termios, baud);
- serial8250_set_afe(port, termios);
- uart_update_timeout(port, termios->c_cflag, baud);
- serial8250_set_errors_and_ignores(port, termios);
- serial8250_set_ier(port, termios);
- serial8250_set_efr(port, termios);
- serial8250_set_divisor(port, baud, quot, frac);
- serial8250_set_fcr(port, termios);
- serial8250_set_mctrl(port, port->mctrl);
-
- uart_port_unlock_irqrestore(port, flags);
- serial8250_rpm_put(up);
+ up->lcr = lcr;
+ serial8250_set_trigger_for_slow_speed(port, termios, baud);
+ serial8250_set_afe(port, termios);
+ uart_update_timeout(port, termios->c_cflag, baud);
+ serial8250_set_errors_and_ignores(port, termios);
+ serial8250_set_ier(port, termios);
+ serial8250_set_efr(port, termios);
+ serial8250_set_divisor(port, baud, quot, frac);
+ serial8250_set_fcr(port, termios);
+ serial8250_set_mctrl(port, port->mctrl);
+ }
/* Don't rewrite B0 */
if (tty_termios_baud_rate(termios))
@@ -2843,15 +2791,13 @@ void serial8250_do_set_ldisc(struct uart_port *port, struct ktermios *termios)
{
if (termios->c_line == N_PPS) {
port->flags |= UPF_HARDPPS_CD;
- uart_port_lock_irq(port);
+ guard(uart_port_lock_irq)(port);
serial8250_enable_ms(port);
- uart_port_unlock_irq(port);
} else {
port->flags &= ~UPF_HARDPPS_CD;
if (!UART_ENABLE_MS(port, termios->c_cflag)) {
- uart_port_lock_irq(port);
+ guard(uart_port_lock_irq)(port);
serial8250_disable_ms(port);
- uart_port_unlock_irq(port);
}
}
}
diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c
index 12a65b7..40a3dbd 100644
--- a/drivers/tty/serial/8250/8250_rsa.c
+++ b/drivers/tty/serial/8250/8250_rsa.c
@@ -140,9 +140,8 @@ void rsa_enable(struct uart_8250_port *up)
return;
if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
- uart_port_lock_irq(&up->port);
+ guard(uart_port_lock_irq)(&up->port);
__rsa_enable(up);
- uart_port_unlock_irq(&up->port);
}
if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
serial_out(up, UART_RSA_FRR, 0);
@@ -165,7 +164,8 @@ void rsa_disable(struct uart_8250_port *up)
if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16)
return;
- uart_port_lock_irq(&up->port);
+ guard(uart_port_lock_irq)(&up->port);
+
mode = serial_in(up, UART_RSA_MSR);
result = !(mode & UART_RSA_MSR_FIFO);
@@ -177,7 +177,6 @@ void rsa_disable(struct uart_8250_port *up)
if (result)
up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
- uart_port_unlock_irq(&up->port);
}
EXPORT_SYMBOL_FOR_MODULES(rsa_disable, "8250_base");
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 4442741..1e27a82 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -928,6 +928,14 @@
Serial console driver for Qualcomm Technologies Inc's GENI based
QUP hardware.
+config SERIAL_QCOM_GENI_UART_PORTS
+ int "Maximum number of GENI UART ports"
+ depends on SERIAL_QCOM_GENI
+ default "8"
+ help
+ Set this to the maximum number of serial ports you want the driver
+ to support.
+
config SERIAL_VT8500
bool "VIA VT8500 on-chip serial port support"
depends on ARCH_VT8500 || COMPILE_TEST
@@ -1412,7 +1420,7 @@
config SERIAL_STM32_CONSOLE
bool "Support for console on STM32"
- depends on SERIAL_STM32=y
+ depends on SERIAL_STM32
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c
index c2cae50..6e19c67 100644
--- a/drivers/tty/serial/ip22zilog.c
+++ b/drivers/tty/serial/ip22zilog.c
@@ -30,6 +30,7 @@
#include <linux/console.h>
#include <linux/spinlock.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/io.h>
#include <asm/irq.h>
@@ -50,8 +51,9 @@
#define ZSDELAY_LONG() udelay(20)
#define ZS_WSYNC(channel) do { } while (0)
-#define NUM_IP22ZILOG 1
-#define NUM_CHANNELS (NUM_IP22ZILOG * 2)
+#define NUM_CHANNELS 2
+#define CHANNEL_B 0
+#define CHANNEL_A 1
#define ZS_CLOCK 3672000 /* Zilog input clock rate. */
#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */
@@ -62,9 +64,6 @@
struct uart_ip22zilog_port {
struct uart_port port;
- /* IRQ servicing chain. */
- struct uart_ip22zilog_port *next;
-
/* Current values of Zilog write registers. */
unsigned char curregs[NUM_ZSREGS];
@@ -72,7 +71,6 @@ struct uart_ip22zilog_port {
#define IP22ZILOG_FLAG_IS_CONS 0x00000004
#define IP22ZILOG_FLAG_IS_KGDB 0x00000008
#define IP22ZILOG_FLAG_MODEM_STATUS 0x00000010
-#define IP22ZILOG_FLAG_IS_CHANNEL_A 0x00000020
#define IP22ZILOG_FLAG_REGS_HELD 0x00000040
#define IP22ZILOG_FLAG_TX_STOPPED 0x00000080
#define IP22ZILOG_FLAG_TX_ACTIVE 0x00000100
@@ -84,6 +82,8 @@ struct uart_ip22zilog_port {
unsigned char prev_status;
};
+static struct uart_ip22zilog_port ip22zilog_port_table[NUM_CHANNELS];
+
#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel *)((PORT)->membase))
#define UART_ZILOG(PORT) ((struct uart_ip22zilog_port *)(PORT))
#define IP22ZILOG_GET_CURR_REG(PORT, REGNUM) \
@@ -93,7 +93,6 @@ struct uart_ip22zilog_port {
#define ZS_IS_CONS(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CONS)
#define ZS_IS_KGDB(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_KGDB)
#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & IP22ZILOG_FLAG_MODEM_STATUS)
-#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CHANNEL_A)
#define ZS_REGS_HELD(UP) ((UP)->flags & IP22ZILOG_FLAG_REGS_HELD)
#define ZS_TX_STOPPED(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_STOPPED)
#define ZS_TX_ACTIVE(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_ACTIVE)
@@ -423,60 +422,57 @@ static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
{
- struct uart_ip22zilog_port *up = dev_id;
+ struct uart_ip22zilog_port *up;
+ struct zilog_channel *channel;
+ unsigned char r3;
+ bool push = false;
- while (up) {
- struct zilog_channel *channel
- = ZILOG_CHANNEL_FROM_PORT(&up->port);
- unsigned char r3;
- bool push = false;
+ up = &ip22zilog_port_table[CHANNEL_A];
+ channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
- uart_port_lock(&up->port);
- r3 = read_zsreg(channel, R3);
+ uart_port_lock(&up->port);
+ r3 = read_zsreg(channel, R3);
- /* Channel A */
- if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
- writeb(RES_H_IUS, &channel->control);
- ZSDELAY();
- ZS_WSYNC(channel);
+ /* Channel A */
+ if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+ writeb(RES_H_IUS, &channel->control);
+ ZSDELAY();
+ ZS_WSYNC(channel);
- if (r3 & CHARxIP)
- push = ip22zilog_receive_chars(up, channel);
- if (r3 & CHAEXT)
- ip22zilog_status_handle(up, channel);
- if (r3 & CHATxIP)
- ip22zilog_transmit_chars(up, channel);
- }
- uart_port_unlock(&up->port);
-
- if (push)
- tty_flip_buffer_push(&up->port.state->port);
-
- /* Channel B */
- up = up->next;
- channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
- push = false;
-
- uart_port_lock(&up->port);
- if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
- writeb(RES_H_IUS, &channel->control);
- ZSDELAY();
- ZS_WSYNC(channel);
-
- if (r3 & CHBRxIP)
- push = ip22zilog_receive_chars(up, channel);
- if (r3 & CHBEXT)
- ip22zilog_status_handle(up, channel);
- if (r3 & CHBTxIP)
- ip22zilog_transmit_chars(up, channel);
- }
- uart_port_unlock(&up->port);
-
- if (push)
- tty_flip_buffer_push(&up->port.state->port);
-
- up = up->next;
+ if (r3 & CHARxIP)
+ push = ip22zilog_receive_chars(up, channel);
+ if (r3 & CHAEXT)
+ ip22zilog_status_handle(up, channel);
+ if (r3 & CHATxIP)
+ ip22zilog_transmit_chars(up, channel);
}
+ uart_port_unlock(&up->port);
+
+ if (push)
+ tty_flip_buffer_push(&up->port.state->port);
+
+ /* Channel B */
+ up = &ip22zilog_port_table[CHANNEL_B];
+ channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+ push = false;
+
+ uart_port_lock(&up->port);
+ if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
+ writeb(RES_H_IUS, &channel->control);
+ ZSDELAY();
+ ZS_WSYNC(channel);
+
+ if (r3 & CHBRxIP)
+ push = ip22zilog_receive_chars(up, channel);
+ if (r3 & CHBEXT)
+ ip22zilog_status_handle(up, channel);
+ if (r3 & CHBTxIP)
+ ip22zilog_transmit_chars(up, channel);
+ }
+ uart_port_unlock(&up->port);
+
+ if (push)
+ tty_flip_buffer_push(&up->port.state->port);
return IRQ_HANDLED;
}
@@ -692,16 +688,16 @@ static void __ip22zilog_reset(struct uart_ip22zilog_port *up)
udelay(100);
}
- if (!ZS_IS_CHANNEL_A(up)) {
- up++;
- channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
- }
+ up = &ip22zilog_port_table[CHANNEL_A];
+ channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
write_zsreg(channel, R9, FHWRES);
ZSDELAY_LONG();
(void) read_zsreg(channel, R0);
up->flags |= IP22ZILOG_FLAG_RESET_DONE;
- up->next->flags |= IP22ZILOG_FLAG_RESET_DONE;
+ up = &ip22zilog_port_table[CHANNEL_B];
+ up->flags |= IP22ZILOG_FLAG_RESET_DONE;
}
static void __ip22zilog_startup(struct uart_ip22zilog_port *up)
@@ -942,47 +938,6 @@ static const struct uart_ops ip22zilog_pops = {
.verify_port = ip22zilog_verify_port,
};
-static struct uart_ip22zilog_port *ip22zilog_port_table;
-static struct zilog_layout **ip22zilog_chip_regs;
-
-static struct uart_ip22zilog_port *ip22zilog_irq_chain;
-static int zilog_irq = -1;
-
-static void * __init alloc_one_table(unsigned long size)
-{
- return kzalloc(size, GFP_KERNEL);
-}
-
-static void __init ip22zilog_alloc_tables(void)
-{
- ip22zilog_port_table = (struct uart_ip22zilog_port *)
- alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port));
- ip22zilog_chip_regs = (struct zilog_layout **)
- alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *));
-
- if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) {
- panic("IP22-Zilog: Cannot allocate IP22-Zilog tables.");
- }
-}
-
-/* Get the address of the registers for IP22-Zilog instance CHIP. */
-static struct zilog_layout * __init get_zs(int chip)
-{
- unsigned long base;
-
- if (chip < 0 || chip >= NUM_IP22ZILOG) {
- panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip);
- }
-
- /* Not probe-able, hard code it. */
- base = (unsigned long) &sgioc->uart;
-
- zilog_irq = SGI_SERIAL_IRQ;
- request_mem_region(base, 8, "IP22-Zilog");
-
- return (struct zilog_layout *) base;
-}
-
#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */
#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
@@ -1070,144 +1025,123 @@ static struct uart_driver ip22zilog_reg = {
#endif
};
-static void __init ip22zilog_prepare(void)
+static void __init ip22zilog_prepare(struct uart_ip22zilog_port *up)
{
unsigned char sysrq_on = IS_ENABLED(CONFIG_SERIAL_IP22_ZILOG_CONSOLE);
- struct uart_ip22zilog_port *up;
- struct zilog_layout *rp;
- int channel, chip;
+ int brg;
- /*
- * Temporary fix.
- */
- for (channel = 0; channel < NUM_CHANNELS; channel++)
- spin_lock_init(&ip22zilog_port_table[channel].port.lock);
+ spin_lock_init(&up->port.lock);
- ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1];
- up = &ip22zilog_port_table[0];
- for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--)
- up[channel].next = &up[channel - 1];
- up[channel].next = NULL;
+ up->port.iotype = UPIO_MEM;
+ up->port.uartclk = ZS_CLOCK;
+ up->port.fifosize = 1;
+ up->port.has_sysrq = sysrq_on;
+ up->port.ops = &ip22zilog_pops;
+ up->port.type = PORT_IP22ZILOG;
- for (chip = 0; chip < NUM_IP22ZILOG; chip++) {
- if (!ip22zilog_chip_regs[chip]) {
- ip22zilog_chip_regs[chip] = rp = get_zs(chip);
-
- up[(chip * 2) + 0].port.membase = (char *) &rp->channelB;
- up[(chip * 2) + 1].port.membase = (char *) &rp->channelA;
-
- /* In theory mapbase is the physical address ... */
- up[(chip * 2) + 0].port.mapbase =
- (unsigned long) ioremap((unsigned long) &rp->channelB, 8);
- up[(chip * 2) + 1].port.mapbase =
- (unsigned long) ioremap((unsigned long) &rp->channelA, 8);
- }
-
- /* Channel A */
- up[(chip * 2) + 0].port.iotype = UPIO_MEM;
- up[(chip * 2) + 0].port.irq = zilog_irq;
- up[(chip * 2) + 0].port.uartclk = ZS_CLOCK;
- up[(chip * 2) + 0].port.fifosize = 1;
- up[(chip * 2) + 0].port.has_sysrq = sysrq_on;
- up[(chip * 2) + 0].port.ops = &ip22zilog_pops;
- up[(chip * 2) + 0].port.type = PORT_IP22ZILOG;
- up[(chip * 2) + 0].port.flags = 0;
- up[(chip * 2) + 0].port.line = (chip * 2) + 0;
- up[(chip * 2) + 0].flags = 0;
-
- /* Channel B */
- up[(chip * 2) + 1].port.iotype = UPIO_MEM;
- up[(chip * 2) + 1].port.irq = zilog_irq;
- up[(chip * 2) + 1].port.uartclk = ZS_CLOCK;
- up[(chip * 2) + 1].port.fifosize = 1;
- up[(chip * 2) + 1].port.has_sysrq = sysrq_on;
- up[(chip * 2) + 1].port.ops = &ip22zilog_pops;
- up[(chip * 2) + 1].port.type = PORT_IP22ZILOG;
- up[(chip * 2) + 1].port.line = (chip * 2) + 1;
- up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
- }
-
- for (channel = 0; channel < NUM_CHANNELS; channel++) {
- struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel];
- int brg;
-
- /* Normal serial TTY. */
- up->parity_mask = 0xff;
- up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
- up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
- up->curregs[R3] = RxENAB | Rx8;
- up->curregs[R5] = TxENAB | Tx8;
- up->curregs[R9] = NV | MIE;
- up->curregs[R10] = NRZ;
- up->curregs[R11] = TCBR | RCBR;
- brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR);
- up->curregs[R12] = (brg & 0xff);
- up->curregs[R13] = (brg >> 8) & 0xff;
- up->curregs[R14] = BRENAB;
- }
+ /* Normal serial TTY. */
+ up->parity_mask = 0xff;
+ up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+ up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+ up->curregs[R3] = RxENAB | Rx8;
+ up->curregs[R5] = TxENAB | Tx8;
+ up->curregs[R9] = NV | MIE;
+ up->curregs[R10] = NRZ;
+ up->curregs[R11] = TCBR | RCBR;
+ brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+ up->curregs[R12] = (brg & 0xff);
+ up->curregs[R13] = (brg >> 8) & 0xff;
+ up->curregs[R14] = BRENAB;
}
-static int __init ip22zilog_ports_init(void)
+static int ip22zilog_probe(struct platform_device *pdev)
{
- int ret;
+ struct uart_ip22zilog_port *up;
+ char __iomem *membase;
+ struct resource *res;
+ int irq;
+ int i;
- printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG);
+ up = &ip22zilog_port_table[CHANNEL_B];
+ if (up->port.dev)
+ return -ENOSPC;
- ip22zilog_prepare();
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
- if (request_irq(zilog_irq, ip22zilog_interrupt, 0,
- "IP22-Zilog", ip22zilog_irq_chain)) {
+ membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(membase))
+ return PTR_ERR(membase);
+
+ ip22zilog_prepare(up);
+
+ up->port.mapbase = res->start + offsetof(struct zilog_layout, channelB);
+ up->port.membase = membase + offsetof(struct zilog_layout, channelB);
+ up->port.line = 0;
+ up->port.dev = &pdev->dev;
+ up->port.irq = irq;
+
+ up = &ip22zilog_port_table[CHANNEL_A];
+ ip22zilog_prepare(up);
+
+ up->port.mapbase = res->start + offsetof(struct zilog_layout, channelA);
+ up->port.membase = membase + offsetof(struct zilog_layout, channelA);
+ up->port.line = 1;
+ up->port.dev = &pdev->dev;
+ up->port.irq = irq;
+
+ if (request_irq(irq, ip22zilog_interrupt, 0,
+ "IP22-Zilog", NULL)) {
panic("IP22-Zilog: Unable to register zs interrupt handler.\n");
}
- ret = uart_register_driver(&ip22zilog_reg);
- if (ret == 0) {
- int i;
-
- for (i = 0; i < NUM_CHANNELS; i++) {
- struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
-
- uart_add_one_port(&ip22zilog_reg, &up->port);
- }
- }
-
- return ret;
-}
-
-static int __init ip22zilog_init(void)
-{
- /* IP22 Zilog setup is hard coded, no probing to do. */
- ip22zilog_alloc_tables();
- ip22zilog_ports_init();
+ for (i = 0; i < NUM_CHANNELS; i++)
+ uart_add_one_port(&ip22zilog_reg,
+ &ip22zilog_port_table[i].port);
return 0;
}
-static void __exit ip22zilog_exit(void)
+static void ip22zilog_remove(struct platform_device *pdev)
{
int i;
- struct uart_ip22zilog_port *up;
for (i = 0; i < NUM_CHANNELS; i++) {
- up = &ip22zilog_port_table[i];
-
- uart_remove_one_port(&ip22zilog_reg, &up->port);
+ uart_remove_one_port(&ip22zilog_reg,
+ &ip22zilog_port_table[i].port);
+ ip22zilog_port_table[i].port.dev = NULL;
}
+}
- /* Free IO mem */
- up = &ip22zilog_port_table[0];
- for (i = 0; i < NUM_IP22ZILOG; i++) {
- if (up[(i * 2) + 0].port.mapbase) {
- iounmap((void*)up[(i * 2) + 0].port.mapbase);
- up[(i * 2) + 0].port.mapbase = 0;
- }
- if (up[(i * 2) + 1].port.mapbase) {
- iounmap((void*)up[(i * 2) + 1].port.mapbase);
- up[(i * 2) + 1].port.mapbase = 0;
- }
+static struct platform_driver ip22zilog_driver = {
+ .probe = ip22zilog_probe,
+ .remove = ip22zilog_remove,
+ .driver = {
+ .name = "ip22zilog"
}
+};
+static int __init ip22zilog_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&ip22zilog_reg);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&ip22zilog_driver);
+ if (ret)
+ uart_unregister_driver(&ip22zilog_reg);
+
+ return ret;
+
+}
+
+static void __exit ip22zilog_exit(void)
+{
uart_unregister_driver(&ip22zilog_reg);
+ platform_driver_unregister(&ip22zilog_driver);
}
module_init(ip22zilog_init);
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index 67d80f8..3faa1b6 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -705,7 +705,7 @@ static int max3100_probe(struct spi_device *spi)
break;
if (i == MAX_MAX3100) {
mutex_unlock(&max3100s_lock);
- return dev_err_probe(dev, -ENOMEM, "too many MAX3100 chips\n");
+ return dev_err_probe(dev, -ENOSPC, "too many MAX3100 chips\n");
}
max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL);
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index ce260e9..ac7d3f1 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -823,17 +823,28 @@ static irqreturn_t max310x_ist(int irq, void *dev_id)
bool handled = false;
if (s->devtype->nr > 1) {
+ bool done;
+
do {
unsigned int val = ~0;
+ unsigned long irq;
+ unsigned int port;
+
+ done = true;
WARN_ON_ONCE(regmap_read(s->regmap,
MAX310X_GLOBALIRQ_REG, &val));
- val = ((1 << s->devtype->nr) - 1) & ~val;
- if (!val)
- break;
- if (max310x_port_irq(s, fls(val) - 1) == IRQ_HANDLED)
- handled = true;
- } while (1);
+
+ irq = val;
+
+ for_each_clear_bit(port, &irq, s->devtype->nr) {
+ done = false;
+
+ if (max310x_port_irq(s, port) == IRQ_HANDLED)
+ handled = true;
+ }
+
+ } while (!done);
} else {
if (max310x_port_irq(s, 0) == IRQ_HANDLED)
handled = true;
@@ -1269,8 +1280,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
/* Alloc port structure */
s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL);
if (!s)
- return dev_err_probe(dev, -ENOMEM,
- "Error allocating port structure\n");
+ return -ENOMEM;
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &uartclk);
@@ -1644,6 +1654,8 @@ static int max310x_i2c_probe(struct i2c_client *client)
port_client = devm_i2c_new_dummy_device(&client->dev,
client->adapter,
port_addr);
+ if (IS_ERR(port_client))
+ return PTR_ERR(port_client);
regcfg_i2c.name = max310x_regmap_name(i);
regmaps[i] = devm_regmap_init_i2c(port_client, ®cfg_i2c);
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 3449945..2e999cb 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -1102,7 +1102,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud,
if (result == baud)
break;
- } else if (entry->divisor > divisor) {
+ } else {
old = target;
target = clk_round_rate(msm_port->clk, old + 1);
/*
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index 5de57b7..8e52be2 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -1264,14 +1264,16 @@ static unsigned long mvebu_uart_clock_recalc_rate(struct clk_hw *hw,
return parent_rate / uart_clock_base->div;
}
-static long mvebu_uart_clock_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int mvebu_uart_clock_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
struct mvebu_uart_clock_base *uart_clock_base =
to_uart_clock_base(uart_clock);
- return *parent_rate / uart_clock_base->div;
+ req->rate = req->best_parent_rate / uart_clock_base->div;
+
+ return 0;
}
static int mvebu_uart_clock_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -1293,7 +1295,7 @@ static const struct clk_ops mvebu_uart_clock_ops = {
.is_enabled = mvebu_uart_clock_is_enabled,
.save_context = mvebu_uart_clock_save_context,
.restore_context = mvebu_uart_clock_restore_context,
- .round_rate = mvebu_uart_clock_round_rate,
+ .determine_rate = mvebu_uart_clock_determine_rate,
.set_rate = mvebu_uart_clock_set_rate,
.recalc_rate = mvebu_uart_clock_recalc_rate,
};
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 32ec632..0fdda3a 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -1,5 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
+/*
+ * Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
/* Disable MMIO tracing to prevent excessive logging of unwanted MMIO traces */
#define __DISABLE_TRACE_MMIO__
@@ -77,7 +80,6 @@
#define STALE_TIMEOUT 16
#define DEFAULT_BITS_PER_CHAR 10
#define GENI_UART_CONS_PORTS 1
-#define GENI_UART_PORTS 3
#define DEF_FIFO_DEPTH_WORDS 16
#define DEF_TX_WM 2
#define DEF_FIFO_WIDTH_BITS 32
@@ -164,33 +166,6 @@ static inline struct qcom_geni_serial_port *to_dev_port(struct uart_port *uport)
return container_of(uport, struct qcom_geni_serial_port, uport);
}
-static struct qcom_geni_serial_port qcom_geni_uart_ports[GENI_UART_PORTS] = {
- [0] = {
- .uport = {
- .iotype = UPIO_MEM,
- .ops = &qcom_geni_uart_pops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- },
- [1] = {
- .uport = {
- .iotype = UPIO_MEM,
- .ops = &qcom_geni_uart_pops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- },
- [2] = {
- .uport = {
- .iotype = UPIO_MEM,
- .ops = &qcom_geni_uart_pops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- },
-};
-
static struct qcom_geni_serial_port qcom_geni_console_port = {
.uport = {
.iotype = UPIO_MEM,
@@ -285,10 +260,10 @@ static const char *qcom_geni_serial_get_type(struct uart_port *uport)
return "MSM";
}
-static struct qcom_geni_serial_port *get_port_from_line(int line, bool console)
+static struct qcom_geni_serial_port *get_port_from_line(int line, bool console, struct device *dev)
{
struct qcom_geni_serial_port *port;
- int nr_ports = console ? GENI_UART_CONS_PORTS : GENI_UART_PORTS;
+ int nr_ports = console ? GENI_UART_CONS_PORTS : CONFIG_SERIAL_QCOM_GENI_UART_PORTS;
if (console) {
if (line < 0 || line >= nr_ports)
@@ -299,14 +274,23 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console)
int max_alias_num = of_alias_get_highest_id("serial");
if (line < 0 || line >= nr_ports)
- line = ida_alloc_range(&port_ida, max_alias_num + 1, nr_ports, GFP_KERNEL);
+ line = ida_alloc_range(&port_ida, max_alias_num + 1,
+ nr_ports - 1, GFP_KERNEL);
else
- line = ida_alloc_range(&port_ida, line, nr_ports, GFP_KERNEL);
+ line = ida_alloc_range(&port_ida, line,
+ nr_ports - 1, GFP_KERNEL);
if (line < 0)
return ERR_PTR(-ENXIO);
- port = &qcom_geni_uart_ports[line];
+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return ERR_PTR(-ENOMEM);
+
+ port->uport.iotype = UPIO_MEM;
+ port->uport.ops = &qcom_geni_uart_pops;
+ port->uport.flags = UPF_BOOT_AUTOCONF;
+ port->uport.line = line;
}
return port;
}
@@ -554,7 +538,7 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
- port = get_port_from_line(co->index, true);
+ port = get_port_from_line(co->index, true, NULL);
if (IS_ERR(port))
return;
@@ -1261,75 +1245,15 @@ static int qcom_geni_serial_startup(struct uart_port *uport)
return 0;
}
-static unsigned long find_clk_rate_in_tol(struct clk *clk, unsigned int desired_clk,
- unsigned int *clk_div, unsigned int percent_tol)
-{
- unsigned long freq;
- unsigned long div, maxdiv;
- u64 mult;
- unsigned long offset, abs_tol, achieved;
-
- abs_tol = div_u64((u64)desired_clk * percent_tol, 100);
- maxdiv = CLK_DIV_MSK >> CLK_DIV_SHFT;
- div = 1;
- while (div <= maxdiv) {
- mult = (u64)div * desired_clk;
- if (mult != (unsigned long)mult)
- break;
-
- offset = div * abs_tol;
- freq = clk_round_rate(clk, mult - offset);
-
- /* Can only get lower if we're done */
- if (freq < mult - offset)
- break;
-
- /*
- * Re-calculate div in case rounding skipped rates but we
- * ended up at a good one, then check for a match.
- */
- div = DIV_ROUND_CLOSEST(freq, desired_clk);
- achieved = DIV_ROUND_CLOSEST(freq, div);
- if (achieved <= desired_clk + abs_tol &&
- achieved >= desired_clk - abs_tol) {
- *clk_div = div;
- return freq;
- }
-
- div = DIV_ROUND_UP(freq, desired_clk);
- }
-
- return 0;
-}
-
-static unsigned long get_clk_div_rate(struct clk *clk, unsigned int baud,
- unsigned int sampling_rate, unsigned int *clk_div)
-{
- unsigned long ser_clk;
- unsigned long desired_clk;
-
- desired_clk = baud * sampling_rate;
- if (!desired_clk)
- return 0;
-
- /*
- * try to find a clock rate within 2% tolerance, then within 5%
- */
- ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 2);
- if (!ser_clk)
- ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 5);
-
- return ser_clk;
-}
-
static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
{
struct qcom_geni_serial_port *port = to_dev_port(uport);
unsigned long clk_rate;
- unsigned int avg_bw_core;
+ unsigned int avg_bw_core, clk_idx;
unsigned int clk_div;
u32 ver, sampling_rate;
u32 ser_clk_cfg;
+ int ret;
sampling_rate = UART_OVERSAMPLING;
/* Sampling rate is halved for IP versions >= 2.5 */
@@ -1337,17 +1261,22 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
if (ver >= QUP_SE_VERSION_2_5)
sampling_rate /= 2;
- clk_rate = get_clk_div_rate(port->se.clk, baud,
- sampling_rate, &clk_div);
- if (!clk_rate) {
- dev_err(port->se.dev,
- "Couldn't find suitable clock rate for %u\n",
- baud * sampling_rate);
+ ret = geni_se_clk_freq_match(&port->se, baud * sampling_rate, &clk_idx, &clk_rate, false);
+ if (ret) {
+ dev_err(port->se.dev, "Failed to find src clk for baud rate: %d ret: %d\n",
+ baud, ret);
+ return ret;
+ }
+
+ clk_div = DIV_ROUND_UP(clk_rate, baud * sampling_rate);
+ /* Check if calculated divider exceeds maximum allowed value */
+ if (clk_div > (CLK_DIV_MSK >> CLK_DIV_SHFT)) {
+ dev_err(port->se.dev, "Calculated clock divider %u exceeds maximum\n", clk_div);
return -EINVAL;
}
- dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n",
- baud * sampling_rate, clk_rate, clk_div);
+ dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n, clk_idx = %u\n",
+ baud * sampling_rate, clk_rate, clk_div, clk_idx);
uport->uartclk = clk_rate;
port->clk_rate = clk_rate;
@@ -1367,6 +1296,8 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG);
writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG);
+ /* Configure clock selection register with the selected clock index */
+ writel(clk_idx & CLK_SEL_MSK, uport->membase + SE_GENI_CLK_SEL);
return 0;
}
@@ -1511,7 +1442,7 @@ static int qcom_geni_console_setup(struct console *co, char *options)
if (co->index >= GENI_UART_CONS_PORTS || co->index < 0)
return -ENXIO;
- port = get_port_from_line(co->index, true);
+ port = get_port_from_line(co->index, true, NULL);
if (IS_ERR(port)) {
pr_err("Invalid line %d\n", co->index);
return PTR_ERR(port);
@@ -1672,7 +1603,7 @@ static struct uart_driver qcom_geni_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "qcom_geni_uart",
.dev_name = "ttyHS",
- .nr = GENI_UART_PORTS,
+ .nr = CONFIG_SERIAL_QCOM_GENI_UART_PORTS,
};
static int geni_serial_resources_on(struct uart_port *uport)
@@ -1866,7 +1797,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
line = of_alias_get_id(pdev->dev.of_node, "hsuart");
}
- port = get_port_from_line(line, data->console);
+ port = get_port_from_line(line, data->console, &pdev->dev);
if (IS_ERR(port)) {
dev_err(&pdev->dev, "Invalid line %d\n", line);
return PTR_ERR(port);
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index a668e0b..1a2c4c1 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -626,7 +626,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
{
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
unsigned int lsr = 0, bytes_read, i;
- bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC) ? true : false;
+ bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC);
u8 ch, flag;
if (unlikely(rxlen >= sizeof(one->buf))) {
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 86d404d..4757293 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -177,15 +177,13 @@ static void uart_start(struct tty_struct *tty)
static void
uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
{
- unsigned long flags;
unsigned int old;
- uart_port_lock_irqsave(port, &flags);
+ guard(uart_port_lock_irqsave)(port);
old = port->mctrl;
port->mctrl = (old & ~clear) | set;
if (old != port->mctrl && !(port->rs485.flags & SER_RS485_ENABLED))
port->ops->set_mctrl(port, port->mctrl);
- uart_port_unlock_irqrestore(port, flags);
}
#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0)
@@ -220,7 +218,7 @@ static void uart_change_line_settings(struct tty_struct *tty, struct uart_state
/*
* Set modem status enables based on termios cflag
*/
- uart_port_lock_irq(uport);
+ guard(uart_port_lock_irq)(uport);
if (termios->c_cflag & CRTSCTS)
uport->status |= UPSTAT_CTS_ENABLE;
else
@@ -241,7 +239,6 @@ static void uart_change_line_settings(struct tty_struct *tty, struct uart_state
else
__uart_start(state);
}
- uart_port_unlock_irq(uport);
}
static int uart_alloc_xmit_buf(struct tty_port *port)
@@ -711,7 +708,6 @@ static void uart_send_xchar(struct tty_struct *tty, u8 ch)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port;
- unsigned long flags;
port = uart_port_ref(state);
if (!port)
@@ -720,11 +716,10 @@ static void uart_send_xchar(struct tty_struct *tty, u8 ch)
if (port->ops->send_xchar)
port->ops->send_xchar(port, ch);
else {
- uart_port_lock_irqsave(port, &flags);
+ guard(uart_port_lock_irqsave)(port);
port->x_char = ch;
if (ch)
port->ops->start_tx(port);
- uart_port_unlock_irqrestore(port, flags);
}
uart_port_deref(port);
}
@@ -1089,7 +1084,6 @@ static int uart_tiocmget(struct tty_struct *tty)
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
struct uart_port *uport;
- int result;
guard(mutex)(&port->mutex);
@@ -1097,12 +1091,9 @@ static int uart_tiocmget(struct tty_struct *tty)
if (!uport || tty_io_error(tty))
return -EIO;
- uart_port_lock_irq(uport);
- result = uport->mctrl;
- result |= uport->ops->get_mctrl(uport);
- uart_port_unlock_irq(uport);
+ guard(uart_port_lock_irq)(uport);
- return result;
+ return uport->mctrl | uport->ops->get_mctrl(uport);
}
static int
@@ -1226,16 +1217,15 @@ static int uart_wait_modem_status(struct uart_state *state, unsigned long arg)
uport = uart_port_ref(state);
if (!uport)
return -EIO;
- uart_port_lock_irq(uport);
- memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
- uart_enable_ms(uport);
- uart_port_unlock_irq(uport);
+ scoped_guard(uart_port_lock_irq, uport) {
+ memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
+ uart_enable_ms(uport);
+ }
add_wait_queue(&port->delta_msr_wait, &wait);
for (;;) {
- uart_port_lock_irq(uport);
- memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
- uart_port_unlock_irq(uport);
+ scoped_guard(uart_port_lock_irq, uport)
+ memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
set_current_state(TASK_INTERRUPTIBLE);
@@ -1430,7 +1420,6 @@ static void uart_set_rs485_rx_during_tx(struct uart_port *port,
static int uart_rs485_config(struct uart_port *port)
{
struct serial_rs485 *rs485 = &port->rs485;
- unsigned long flags;
int ret;
if (!(rs485->flags & SER_RS485_ENABLED))
@@ -1440,9 +1429,8 @@ static int uart_rs485_config(struct uart_port *port)
uart_set_rs485_termination(port, rs485);
uart_set_rs485_rx_during_tx(port, rs485);
- uart_port_lock_irqsave(port, &flags);
- ret = port->rs485_config(port, NULL, rs485);
- uart_port_unlock_irqrestore(port, flags);
+ scoped_guard(uart_port_lock_irqsave, port)
+ ret = port->rs485_config(port, NULL, rs485);
if (ret) {
memset(rs485, 0, sizeof(*rs485));
/* unset GPIOs */
@@ -1456,12 +1444,10 @@ static int uart_rs485_config(struct uart_port *port)
static int uart_get_rs485_config(struct uart_port *port,
struct serial_rs485 __user *rs485)
{
- unsigned long flags;
struct serial_rs485 aux;
- uart_port_lock_irqsave(port, &flags);
- aux = port->rs485;
- uart_port_unlock_irqrestore(port, flags);
+ scoped_guard(uart_port_lock_irqsave, port)
+ aux = port->rs485;
if (copy_to_user(rs485, &aux, sizeof(aux)))
return -EFAULT;
@@ -1474,7 +1460,6 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
{
struct serial_rs485 rs485;
int ret;
- unsigned long flags;
if (!(port->rs485_supported.flags & SER_RS485_ENABLED))
return -ENOTTY;
@@ -1489,16 +1474,16 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
uart_set_rs485_termination(port, &rs485);
uart_set_rs485_rx_during_tx(port, &rs485);
- uart_port_lock_irqsave(port, &flags);
- ret = port->rs485_config(port, &tty->termios, &rs485);
- if (!ret) {
- port->rs485 = rs485;
+ scoped_guard(uart_port_lock_irqsave, port) {
+ ret = port->rs485_config(port, &tty->termios, &rs485);
+ if (!ret) {
+ port->rs485 = rs485;
- /* Reset RTS and other mctrl lines when disabling RS485 */
- if (!(rs485.flags & SER_RS485_ENABLED))
- port->ops->set_mctrl(port, port->mctrl);
+ /* Reset RTS and other mctrl lines when disabling RS485 */
+ if (!(rs485.flags & SER_RS485_ENABLED))
+ port->ops->set_mctrl(port, port->mctrl);
+ }
}
- uart_port_unlock_irqrestore(port, flags);
if (ret) {
/* restore old GPIO settings */
gpiod_set_value_cansleep(port->rs485_term_gpio,
@@ -1517,15 +1502,13 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
static int uart_get_iso7816_config(struct uart_port *port,
struct serial_iso7816 __user *iso7816)
{
- unsigned long flags;
struct serial_iso7816 aux;
if (!port->iso7816_config)
return -ENOTTY;
- uart_port_lock_irqsave(port, &flags);
- aux = port->iso7816;
- uart_port_unlock_irqrestore(port, flags);
+ scoped_guard(uart_port_lock_irqsave, port)
+ aux = port->iso7816;
if (copy_to_user(iso7816, &aux, sizeof(aux)))
return -EFAULT;
@@ -1537,8 +1520,7 @@ static int uart_set_iso7816_config(struct uart_port *port,
struct serial_iso7816 __user *iso7816_user)
{
struct serial_iso7816 iso7816;
- int i, ret;
- unsigned long flags;
+ int i;
if (!port->iso7816_config)
return -ENOTTY;
@@ -1554,11 +1536,11 @@ static int uart_set_iso7816_config(struct uart_port *port,
if (iso7816.reserved[i])
return -EINVAL;
- uart_port_lock_irqsave(port, &flags);
- ret = port->iso7816_config(port, &iso7816);
- uart_port_unlock_irqrestore(port, flags);
- if (ret)
- return ret;
+ scoped_guard(uart_port_lock_irqsave, port) {
+ int ret = port->iso7816_config(port, &iso7816);
+ if (ret)
+ return ret;
+ }
if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816)))
return -EFAULT;
@@ -1770,9 +1752,8 @@ static void uart_tty_port_shutdown(struct tty_port *port)
if (WARN(!uport, "detached port still initialized!\n"))
return;
- uart_port_lock_irq(uport);
- uport->ops->stop_rx(uport);
- uart_port_unlock_irq(uport);
+ scoped_guard(uart_port_lock_irq, uport)
+ uport->ops->stop_rx(uport);
serial_base_port_shutdown(uport);
uart_port_shutdown(port);
@@ -2044,9 +2025,8 @@ static void uart_line_info(struct seq_file *m, struct uart_state *state)
pm_state = state->pm_state;
if (pm_state != UART_PM_STATE_ON)
uart_change_pm(state, UART_PM_STATE_ON);
- uart_port_lock_irq(uport);
- status = uport->ops->get_mctrl(uport);
- uart_port_unlock_irq(uport);
+ scoped_guard(uart_port_lock_irq, uport)
+ status = uport->ops->get_mctrl(uport);
if (pm_state != UART_PM_STATE_ON)
uart_change_pm(state, pm_state);
@@ -2355,9 +2335,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
*/
if (!console_suspend_enabled && uart_console(uport)) {
if (uport->ops->start_rx) {
- uart_port_lock_irq(uport);
+ guard(uart_port_lock_irq)(uport);
uport->ops->stop_rx(uport);
- uart_port_unlock_irq(uport);
}
device_set_awake_path(uport->dev);
return 0;
@@ -2373,15 +2352,15 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
tty_port_set_suspended(port, true);
tty_port_set_initialized(port, false);
- uart_port_lock_irq(uport);
- ops->stop_tx(uport);
- if (!(uport->rs485.flags & SER_RS485_ENABLED))
- ops->set_mctrl(uport, 0);
- /* save mctrl so it can be restored on resume */
- mctrl = uport->mctrl;
- uport->mctrl = 0;
- ops->stop_rx(uport);
- uart_port_unlock_irq(uport);
+ scoped_guard(uart_port_lock_irq, uport) {
+ ops->stop_tx(uport);
+ if (!(uport->rs485.flags & SER_RS485_ENABLED))
+ ops->set_mctrl(uport, 0);
+ /* save mctrl so it can be restored on resume */
+ mctrl = uport->mctrl;
+ uport->mctrl = 0;
+ ops->stop_rx(uport);
+ }
/*
* Wait for the transmitter to empty.
@@ -2450,9 +2429,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
uart_change_pm(state, UART_PM_STATE_ON);
uport->ops->set_termios(uport, &termios, NULL);
if (!console_suspend_enabled && uport->ops->start_rx) {
- uart_port_lock_irq(uport);
+ guard(uart_port_lock_irq)(uport);
uport->ops->start_rx(uport);
- uart_port_unlock_irq(uport);
}
if (console_suspend_enabled)
console_resume(uport->cons);
@@ -2463,10 +2441,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
int ret;
uart_change_pm(state, UART_PM_STATE_ON);
- uart_port_lock_irq(uport);
- if (!(uport->rs485.flags & SER_RS485_ENABLED))
- ops->set_mctrl(uport, 0);
- uart_port_unlock_irq(uport);
+ scoped_guard(uart_port_lock_irq, uport)
+ if (!(uport->rs485.flags & SER_RS485_ENABLED))
+ ops->set_mctrl(uport, 0);
if (console_suspend_enabled || !uart_console(uport)) {
/* Protected by port mutex for now */
struct tty_struct *tty = port->tty;
@@ -2476,11 +2453,11 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
if (tty)
uart_change_line_settings(tty, state, NULL);
uart_rs485_config(uport);
- uart_port_lock_irq(uport);
- if (!(uport->rs485.flags & SER_RS485_ENABLED))
- ops->set_mctrl(uport, uport->mctrl);
- ops->start_tx(uport);
- uart_port_unlock_irq(uport);
+ scoped_guard(uart_port_lock_irq, uport) {
+ if (!(uport->rs485.flags & SER_RS485_ENABLED))
+ ops->set_mctrl(uport, uport->mctrl);
+ ops->start_tx(uport);
+ }
tty_port_set_initialized(port, true);
} else {
/*
@@ -2574,8 +2551,6 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
}
if (port->type != PORT_UNKNOWN) {
- unsigned long flags;
-
uart_report_port(drv, port);
/* Synchronize with possible boot console. */
@@ -2590,11 +2565,11 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
* keep the DTR setting that is set in uart_set_options()
* We probably don't need a spinlock around this, but
*/
- uart_port_lock_irqsave(port, &flags);
- port->mctrl &= TIOCM_DTR;
- if (!(port->rs485.flags & SER_RS485_ENABLED))
- port->ops->set_mctrl(port, port->mctrl);
- uart_port_unlock_irqrestore(port, flags);
+ scoped_guard(uart_port_lock_irqsave, port) {
+ port->mctrl &= TIOCM_DTR;
+ if (!(port->rs485.flags & SER_RS485_ENABLED))
+ port->ops->set_mctrl(port, port->mctrl);
+ }
uart_rs485_config(port);
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 97f8a9a..1f78b0d 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -1133,8 +1133,7 @@ static int sysrq_sysctl_handler(const struct ctl_table *table, int write,
* Behaves like do_proc_dointvec as t does not have min nor max.
*/
ret = proc_dointvec_minmax(&t, write, buffer, lenp, ppos);
-
- if (ret || !write)
+ if (ret)
return ret;
if (write)
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 5b4d5fb..fe67c5c 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -63,12 +63,8 @@ static void tty_port_default_lookahead_buf(struct tty_port *port, const u8 *p,
static void tty_port_default_wakeup(struct tty_port *port)
{
- struct tty_struct *tty = tty_port_tty_get(port);
-
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
+ scoped_guard(tty_port_tty, port)
+ tty_wakeup(scoped_tty());
}
const struct tty_port_client_operations tty_port_default_client_ops = {
@@ -225,26 +221,27 @@ EXPORT_SYMBOL_GPL(tty_port_unregister_device);
int tty_port_alloc_xmit_buf(struct tty_port *port)
{
/* We may sleep in get_zeroed_page() */
- mutex_lock(&port->buf_mutex);
- if (port->xmit_buf == NULL) {
- port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL);
- if (port->xmit_buf)
- kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE);
- }
- mutex_unlock(&port->buf_mutex);
+ guard(mutex)(&port->buf_mutex);
+
+ if (port->xmit_buf)
+ return 0;
+
+ port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL);
if (port->xmit_buf == NULL)
return -ENOMEM;
+
+ kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE);
+
return 0;
}
EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
void tty_port_free_xmit_buf(struct tty_port *port)
{
- mutex_lock(&port->buf_mutex);
+ guard(mutex)(&port->buf_mutex);
free_page((unsigned long)port->xmit_buf);
port->xmit_buf = NULL;
INIT_KFIFO(port->xmit_fifo);
- mutex_unlock(&port->buf_mutex);
}
EXPORT_SYMBOL(tty_port_free_xmit_buf);
@@ -301,13 +298,8 @@ EXPORT_SYMBOL(tty_port_put);
*/
struct tty_struct *tty_port_tty_get(struct tty_port *port)
{
- unsigned long flags;
- struct tty_struct *tty;
-
- spin_lock_irqsave(&port->lock, flags);
- tty = tty_kref_get(port->tty);
- spin_unlock_irqrestore(&port->lock, flags);
- return tty;
+ guard(spinlock_irqsave)(&port->lock);
+ return tty_kref_get(port->tty);
}
EXPORT_SYMBOL(tty_port_tty_get);
@@ -321,12 +313,9 @@ EXPORT_SYMBOL(tty_port_tty_get);
*/
void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
{
- unsigned long flags;
-
- spin_lock_irqsave(&port->lock, flags);
+ guard(spinlock_irqsave)(&port->lock);
tty_kref_put(port->tty);
port->tty = tty_kref_get(tty);
- spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL(tty_port_tty_set);
@@ -342,24 +331,24 @@ EXPORT_SYMBOL(tty_port_tty_set);
*/
static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
{
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
+
if (port->console)
- goto out;
+ return;
- if (tty_port_initialized(port)) {
- tty_port_set_initialized(port, false);
- /*
- * Drop DTR/RTS if HUPCL is set. This causes any attached
- * modem to hang up the line.
- */
- if (tty && C_HUPCL(tty))
- tty_port_lower_dtr_rts(port);
+ if (!tty_port_initialized(port))
+ return;
- if (port->ops->shutdown)
- port->ops->shutdown(port);
- }
-out:
- mutex_unlock(&port->mutex);
+ tty_port_set_initialized(port, false);
+ /*
+ * Drop DTR/RTS if HUPCL is set. This causes any attached
+ * modem to hang up the line.
+ */
+ if (tty && C_HUPCL(tty))
+ tty_port_lower_dtr_rts(port);
+
+ if (port->ops->shutdown)
+ port->ops->shutdown(port);
}
/**
@@ -374,15 +363,15 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
void tty_port_hangup(struct tty_port *port)
{
struct tty_struct *tty;
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
- port->count = 0;
- tty = port->tty;
- if (tty)
- set_bit(TTY_IO_ERROR, &tty->flags);
- port->tty = NULL;
- spin_unlock_irqrestore(&port->lock, flags);
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ port->count = 0;
+ tty = port->tty;
+ if (tty)
+ set_bit(TTY_IO_ERROR, &tty->flags);
+ port->tty = NULL;
+ }
+
tty_port_set_active(port, false);
tty_port_shutdown(port, tty);
tty_kref_put(tty);
@@ -393,15 +382,16 @@ EXPORT_SYMBOL(tty_port_hangup);
void __tty_port_tty_hangup(struct tty_port *port, bool check_clocal, bool async)
{
- struct tty_struct *tty = tty_port_tty_get(port);
+ scoped_guard(tty_port_tty, port) {
+ struct tty_struct *tty = scoped_tty();
- if (tty && (!check_clocal || !C_CLOCAL(tty))) {
- if (async)
- tty_hangup(tty);
- else
- tty_vhangup(tty);
+ if (!check_clocal || !C_CLOCAL(tty)) {
+ if (async)
+ tty_hangup(tty);
+ else
+ tty_vhangup(tty);
+ }
}
- tty_kref_put(tty);
}
EXPORT_SYMBOL_GPL(__tty_port_tty_hangup);
@@ -490,7 +480,6 @@ int tty_port_block_til_ready(struct tty_port *port,
struct tty_struct *tty, struct file *filp)
{
int do_clocal = 0, retval;
- unsigned long flags;
DEFINE_WAIT(wait);
/* if non-blocking mode is set we can pass directly to open unless
@@ -519,10 +508,10 @@ int tty_port_block_til_ready(struct tty_port *port,
retval = 0;
/* The port lock protects the port counts */
- spin_lock_irqsave(&port->lock, flags);
- port->count--;
- port->blocked_open++;
- spin_unlock_irqrestore(&port->lock, flags);
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ port->count--;
+ port->blocked_open++;
+ }
while (1) {
/* Indicate we are open */
@@ -561,11 +550,11 @@ int tty_port_block_til_ready(struct tty_port *port,
/* Update counts. A parallel hangup will have set count to zero and
* we must not mess that up further.
*/
- spin_lock_irqsave(&port->lock, flags);
- if (!tty_hung_up_p(filp))
- port->count++;
- port->blocked_open--;
- spin_unlock_irqrestore(&port->lock, flags);
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ if (!tty_hung_up_p(filp))
+ port->count++;
+ port->blocked_open--;
+ }
if (retval == 0)
tty_port_set_active(port, true);
return retval;
@@ -604,28 +593,24 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
int tty_port_close_start(struct tty_port *port,
struct tty_struct *tty, struct file *filp)
{
- unsigned long flags;
-
if (tty_hung_up_p(filp))
return 0;
- spin_lock_irqsave(&port->lock, flags);
- if (tty->count == 1 && port->count != 1) {
- tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__,
- port->count);
- port->count = 1;
- }
- if (--port->count < 0) {
- tty_warn(tty, "%s: bad port count (%d)\n", __func__,
- port->count);
- port->count = 0;
- }
+ scoped_guard(spinlock_irqsave, &port->lock) {
+ if (tty->count == 1 && port->count != 1) {
+ tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__,
+ port->count);
+ port->count = 1;
+ }
+ if (--port->count < 0) {
+ tty_warn(tty, "%s: bad port count (%d)\n", __func__,
+ port->count);
+ port->count = 0;
+ }
- if (port->count) {
- spin_unlock_irqrestore(&port->lock, flags);
- return 0;
+ if (port->count)
+ return 0;
}
- spin_unlock_irqrestore(&port->lock, flags);
tty->closing = 1;
@@ -744,9 +729,8 @@ EXPORT_SYMBOL_GPL(tty_port_install);
int tty_port_open(struct tty_port *port, struct tty_struct *tty,
struct file *filp)
{
- spin_lock_irq(&port->lock);
- ++port->count;
- spin_unlock_irq(&port->lock);
+ scoped_guard(spinlock_irq, &port->lock)
+ ++port->count;
tty_port_tty_set(port, tty);
/*
@@ -755,21 +739,17 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
* port mutex.
*/
- mutex_lock(&port->mutex);
-
- if (!tty_port_initialized(port)) {
+ scoped_guard(mutex, &port->mutex) {
+ if (tty_port_initialized(port))
+ break;
clear_bit(TTY_IO_ERROR, &tty->flags);
if (port->ops->activate) {
int retval = port->ops->activate(port, tty);
-
- if (retval) {
- mutex_unlock(&port->mutex);
+ if (retval)
return retval;
- }
}
tty_port_set_initialized(port, true);
}
- mutex_unlock(&port->mutex);
return tty_port_block_til_ready(port, tty, filp);
}
EXPORT_SYMBOL(tty_port_open);
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index bb4bb27..7a11c3f 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -361,10 +361,10 @@ int con_set_trans_old(unsigned char __user * arg)
inbuf[i] = UNI_DIRECT_BASE | ch;
}
- console_lock();
+ guard(console_lock)();
memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
update_user_maps();
- console_unlock();
+
return 0;
}
@@ -374,13 +374,11 @@ int con_get_trans_old(unsigned char __user * arg)
unsigned short *p = translations[USER_MAP];
unsigned char outbuf[E_TABSZ];
- console_lock();
- for (i = 0; i < ARRAY_SIZE(outbuf); i++)
- {
- ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
- outbuf[i] = (ch & ~0xff) ? 0 : ch;
- }
- console_unlock();
+ scoped_guard(console_lock)
+ for (i = 0; i < ARRAY_SIZE(outbuf); i++) {
+ ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
+ outbuf[i] = (ch & ~0xff) ? 0 : ch;
+ }
return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0;
}
@@ -392,10 +390,10 @@ int con_set_trans_new(ushort __user * arg)
if (copy_from_user(inbuf, arg, sizeof(inbuf)))
return -EFAULT;
- console_lock();
+ guard(console_lock)();
memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
update_user_maps();
- console_unlock();
+
return 0;
}
@@ -403,9 +401,8 @@ int con_get_trans_new(ushort __user * arg)
{
unsigned short outbuf[E_TABSZ];
- console_lock();
- memcpy(outbuf, translations[USER_MAP], sizeof(outbuf));
- console_unlock();
+ scoped_guard(console_lock)
+ memcpy(outbuf, translations[USER_MAP], sizeof(outbuf));
return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0;
}
@@ -571,11 +568,8 @@ static int con_do_clear_unimap(struct vc_data *vc)
int con_clear_unimap(struct vc_data *vc)
{
- int ret;
- console_lock();
- ret = con_do_clear_unimap(vc);
- console_unlock();
- return ret;
+ guard(console_lock)();
+ return con_do_clear_unimap(vc);
}
static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc,
@@ -637,32 +631,28 @@ static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc,
int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
{
- int err = 0, err1;
struct uni_pagedict *dict;
- struct unipair *unilist, *plist;
+ struct unipair *plist;
+ int err = 0;
if (!ct)
return 0;
- unilist = vmemdup_array_user(list, ct, sizeof(*unilist));
+ struct unipair *unilist __free(kvfree) = vmemdup_array_user(list, ct, sizeof(*unilist));
if (IS_ERR(unilist))
return PTR_ERR(unilist);
- console_lock();
+ guard(console_lock)();
/* Save original vc_unipagdir_loc in case we allocate a new one */
dict = *vc->uni_pagedict_loc;
- if (!dict) {
- err = -EINVAL;
- goto out_unlock;
- }
+ if (!dict)
+ return -EINVAL;
if (dict->refcount > 1) {
dict = con_unshare_unimap(vc, dict);
- if (IS_ERR(dict)) {
- err = PTR_ERR(dict);
- goto out_unlock;
- }
+ if (IS_ERR(dict))
+ return PTR_ERR(dict);
} else if (dict == dflt) {
dflt = NULL;
}
@@ -671,7 +661,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
* Insert user specified unicode pairs into new table.
*/
for (plist = unilist; ct; ct--, plist++) {
- err1 = con_insert_unipair(dict, plist->unicode, plist->fontpos);
+ int err1 = con_insert_unipair(dict, plist->unicode, plist->fontpos);
if (err1)
err = err1;
}
@@ -680,15 +670,12 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
* Merge with fontmaps of any other virtual consoles.
*/
if (con_unify_unimap(vc, dict))
- goto out_unlock;
+ return err;
for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++)
set_inverse_transl(vc, dict, m);
set_inverse_trans_unicode(dict);
-out_unlock:
- console_unlock();
- kvfree(unilist);
return err;
}
@@ -787,50 +774,49 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct,
{
ushort ect;
struct uni_pagedict *dict;
- struct unipair *unilist;
unsigned int d, r, g;
- int ret = 0;
- unilist = kvmalloc_array(ct, sizeof(*unilist), GFP_KERNEL);
+ struct unipair *unilist __free(kvfree) = kvmalloc_array(ct, sizeof(*unilist), GFP_KERNEL);
if (!unilist)
return -ENOMEM;
- console_lock();
+ scoped_guard(console_lock) {
+ ect = 0;
+ dict = *vc->uni_pagedict_loc;
+ if (!dict)
+ break;
- ect = 0;
- dict = *vc->uni_pagedict_loc;
- if (!dict)
- goto unlock;
-
- for (d = 0; d < UNI_DIRS; d++) {
- u16 **dir = dict->uni_pgdir[d];
- if (!dir)
- continue;
-
- for (r = 0; r < UNI_DIR_ROWS; r++) {
- u16 *row = dir[r];
- if (!row)
+ for (d = 0; d < UNI_DIRS; d++) {
+ u16 **dir = dict->uni_pgdir[d];
+ if (!dir)
continue;
- for (g = 0; g < UNI_ROW_GLYPHS; g++, row++) {
- if (*row >= MAX_GLYPH)
+ for (r = 0; r < UNI_DIR_ROWS; r++) {
+ u16 *row = dir[r];
+ if (!row)
continue;
- if (ect < ct) {
- unilist[ect].unicode = UNI(d, r, g);
- unilist[ect].fontpos = *row;
+
+ for (g = 0; g < UNI_ROW_GLYPHS; g++, row++) {
+ if (*row >= MAX_GLYPH)
+ continue;
+ if (ect < ct) {
+ unilist[ect].unicode = UNI(d, r, g);
+ unilist[ect].fontpos = *row;
+ }
+ ect++;
}
- ect++;
}
}
}
-unlock:
- console_unlock();
+
if (copy_to_user(list, unilist, min(ect, ct) * sizeof(*unilist)))
- ret = -EFAULT;
+ return -EFAULT;
if (put_user(ect, uct))
- ret = -EFAULT;
- kvfree(unilist);
- return ret ? ret : (ect <= ct) ? 0 : -ENOMEM;
+ return -EFAULT;
+ if (ect > ct)
+ return -ENOMEM;
+
+ return 0;
}
/*
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 24b0a53..07d3b93 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -127,9 +127,8 @@ int sel_loadlut(u32 __user *lut)
if (copy_from_user(tmplut, lut, sizeof(inwordLut)))
return -EFAULT;
- console_lock();
+ guard(console_lock)();
memcpy(inwordLut, tmplut, sizeof(inwordLut));
- console_unlock();
return 0;
}
@@ -375,15 +374,9 @@ static int vc_selection(struct vc_data *vc, struct tiocl_selection *v,
int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
{
- int ret;
-
- mutex_lock(&vc_sel.lock);
- console_lock();
- ret = vc_selection(vc_cons[fg_console].d, v, tty);
- console_unlock();
- mutex_unlock(&vc_sel.lock);
-
- return ret;
+ guard(mutex)(&vc_sel.lock);
+ guard(console_lock)();
+ return vc_selection(vc_cons[fg_console].d, v, tty);
}
EXPORT_SYMBOL_GPL(set_selection_kernel);
@@ -409,9 +402,8 @@ int paste_selection(struct tty_struct *tty)
const char *bps = bp ? bracketed_paste_start : NULL;
const char *bpe = bp ? bracketed_paste_end : NULL;
- console_lock();
- poke_blanked_console();
- console_unlock();
+ scoped_guard(console_lock)
+ poke_blanked_console();
ld = tty_ldisc_ref_wait(tty);
if (!ld)
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index 79b33d9..c814644 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -53,6 +53,8 @@
#define HEADER_SIZE 4u
#define CON_BUF_SIZE (IS_ENABLED(CONFIG_BASE_SMALL) ? 256 : PAGE_SIZE)
+DEFINE_FREE(free_page_ptr, void *, if (_T) free_page((unsigned long)_T));
+
/*
* Our minor space:
*
@@ -72,7 +74,6 @@
#define use_unicode(inode) (iminor(inode) & 64)
#define use_attributes(inode) (iminor(inode) & 128)
-
struct vcs_poll_data {
struct notifier_block notifier;
unsigned int cons_num;
@@ -231,15 +232,13 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
struct vc_data *vc;
int size;
- console_lock();
- vc = vcs_vc(inode, NULL);
- if (!vc) {
- console_unlock();
- return -ENXIO;
- }
+ scoped_guard(console_lock) {
+ vc = vcs_vc(inode, NULL);
+ if (!vc)
+ return -ENXIO;
- size = vcs_size(vc, use_attributes(inode), use_unicode(inode));
- console_unlock();
+ size = vcs_size(vc, use_attributes(inode), use_unicode(inode));
+ }
if (size < 0)
return size;
return fixed_size_llseek(file, offset, orig, size);
@@ -369,11 +368,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
struct vcs_poll_data *poll;
unsigned int read;
ssize_t ret;
- char *con_buf;
loff_t pos;
bool viewed, attr, uni_mode;
- con_buf = (char *) __get_free_page(GFP_KERNEL);
+ char *con_buf __free(free_page_ptr) = (char *)__get_free_page(GFP_KERNEL);
if (!con_buf)
return -ENOMEM;
@@ -382,17 +380,16 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
/* Select the proper current console and verify
* sanity of the situation under the console lock.
*/
- console_lock();
+ guard(console_lock)();
uni_mode = use_unicode(inode);
attr = use_attributes(inode);
- ret = -EINVAL;
if (pos < 0)
- goto unlock_out;
+ return -EINVAL;
/* we enforce 32-bit alignment for pos and count in unicode mode */
if (uni_mode && (pos | count) & 3)
- goto unlock_out;
+ return -EINVAL;
poll = file->private_data;
if (count && poll)
@@ -468,10 +465,8 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
}
*ppos += read;
if (read)
- ret = read;
-unlock_out:
- console_unlock();
- free_page((unsigned long) con_buf);
+ return read;
+
return ret;
}
@@ -591,7 +586,6 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
struct inode *inode = file_inode(file);
struct vc_data *vc;
- char *con_buf;
u16 *org0, *org;
unsigned int written;
int size;
@@ -602,7 +596,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
if (use_unicode(inode))
return -EOPNOTSUPP;
- con_buf = (char *) __get_free_page(GFP_KERNEL);
+ char *con_buf __free(free_page_ptr) = (char *)__get_free_page(GFP_KERNEL);
if (!con_buf)
return -ENOMEM;
@@ -611,22 +605,18 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
/* Select the proper current console and verify
* sanity of the situation under the console lock.
*/
- console_lock();
+ guard(console_lock)();
attr = use_attributes(inode);
- ret = -ENXIO;
vc = vcs_vc(inode, &viewed);
if (!vc)
- goto unlock_out;
+ return -ENXIO;
size = vcs_size(vc, attr, false);
- if (size < 0) {
- ret = size;
- goto unlock_out;
- }
- ret = -EINVAL;
+ if (size < 0)
+ return size;
if (pos < 0 || pos > size)
- goto unlock_out;
+ return -EINVAL;
if (count > size - pos)
count = size - pos;
written = 0;
@@ -651,8 +641,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
*/
if (written)
break;
- ret = -EFAULT;
- goto unlock_out;
+ return -EFAULT;
}
}
@@ -664,15 +653,13 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
if (!vc) {
if (written)
break;
- ret = -ENXIO;
- goto unlock_out;
+ return -ENXIO;
}
size = vcs_size(vc, attr, false);
if (size < 0) {
if (written)
break;
- ret = size;
- goto unlock_out;
+ return size;
}
if (pos >= size)
break;
@@ -702,9 +689,6 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
if (written)
vcs_scr_updated(vc);
-unlock_out:
- console_unlock();
- free_page((unsigned long) con_buf);
return ret;
}
@@ -754,17 +738,17 @@ vcs_open(struct inode *inode, struct file *filp)
unsigned int currcons = console(inode);
bool attr = use_attributes(inode);
bool uni_mode = use_unicode(inode);
- int ret = 0;
/* we currently don't support attributes in unicode mode */
if (attr && uni_mode)
return -EOPNOTSUPP;
- console_lock();
- if(currcons && !vc_cons_allocated(currcons-1))
- ret = -ENXIO;
- console_unlock();
- return ret;
+ guard(console_lock)();
+
+ if (currcons && !vc_cons_allocated(currcons - 1))
+ return -ENXIO;
+
+ return 0;
}
static int vcs_release(struct inode *inode, struct file *file)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 62049ce..6e0089b 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -141,6 +141,7 @@ static const struct consw *con_driver_map[MAX_NR_CONSOLES];
static int con_open(struct tty_struct *, struct file *);
static void vc_init(struct vc_data *vc, int do_clear);
static void gotoxy(struct vc_data *vc, int new_x, int new_y);
+static void restore_cur(struct vc_data *vc);
static void save_cur(struct vc_data *vc);
static void reset_terminal(struct vc_data *vc, int do_clear);
static void con_flush_chars(struct tty_struct *tty);
@@ -1317,12 +1318,9 @@ EXPORT_SYMBOL(__vc_resize);
static int vt_resize(struct tty_struct *tty, struct winsize *ws)
{
struct vc_data *vc = tty->driver_data;
- int ret;
- console_lock();
- ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row, false);
- console_unlock();
- return ret;
+ guard(console_lock)();
+ return vc_do_resize(tty, vc, ws->ws_col, ws->ws_row, false);
}
struct vc_data *vc_deallocate(unsigned int currcons)
@@ -1343,6 +1341,10 @@ struct vc_data *vc_deallocate(unsigned int currcons)
vc_uniscr_set(vc, NULL);
kfree(vc->vc_screenbuf);
vc_cons[currcons].d = NULL;
+ if (vc->vc_saved_screen != NULL) {
+ kfree(vc->vc_saved_screen);
+ vc->vc_saved_screen = NULL;
+ }
}
return vc;
}
@@ -1878,6 +1880,45 @@ static int get_bracketed_paste(struct tty_struct *tty)
return vc->vc_bracketed_paste;
}
+/* console_lock is held */
+static void enter_alt_screen(struct vc_data *vc)
+{
+ unsigned int size = vc->vc_rows * vc->vc_cols * 2;
+
+ if (vc->vc_saved_screen != NULL)
+ return; /* Already inside an alt-screen */
+ vc->vc_saved_screen = kmemdup((u16 *)vc->vc_origin, size, GFP_KERNEL);
+ if (vc->vc_saved_screen == NULL)
+ return;
+ vc->vc_saved_rows = vc->vc_rows;
+ vc->vc_saved_cols = vc->vc_cols;
+ save_cur(vc);
+ /* clear entire screen */
+ csi_J(vc, CSI_J_FULL);
+}
+
+/* console_lock is held */
+static void leave_alt_screen(struct vc_data *vc)
+{
+ unsigned int rows = min(vc->vc_saved_rows, vc->vc_rows);
+ unsigned int cols = min(vc->vc_saved_cols, vc->vc_cols);
+ u16 *src, *dest;
+
+ if (vc->vc_saved_screen == NULL)
+ return; /* Not inside an alt-screen */
+ for (unsigned int r = 0; r < rows; r++) {
+ src = vc->vc_saved_screen + r * vc->vc_saved_cols;
+ dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols;
+ memcpy(dest, src, 2 * cols);
+ }
+ restore_cur(vc);
+ /* Update the entire screen */
+ if (con_should_update(vc))
+ do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+ kfree(vc->vc_saved_screen);
+ vc->vc_saved_screen = NULL;
+}
+
enum {
CSI_DEC_hl_CURSOR_KEYS = 1, /* CKM: cursor keys send ^[Ox/^[[x */
CSI_DEC_hl_132_COLUMNS = 3, /* COLM: 80/132 mode switch */
@@ -1888,6 +1929,7 @@ enum {
CSI_DEC_hl_MOUSE_X10 = 9,
CSI_DEC_hl_SHOW_CURSOR = 25, /* TCEM */
CSI_DEC_hl_MOUSE_VT200 = 1000,
+ CSI_DEC_hl_ALT_SCREEN = 1049,
CSI_DEC_hl_BRACKETED_PASTE = 2004,
};
@@ -1944,6 +1986,12 @@ static void csi_DEC_hl(struct vc_data *vc, bool on_off)
case CSI_DEC_hl_BRACKETED_PASTE:
vc->vc_bracketed_paste = on_off;
break;
+ case CSI_DEC_hl_ALT_SCREEN:
+ if (on_off)
+ enter_alt_screen(vc);
+ else
+ leave_alt_screen(vc);
+ break;
}
}
@@ -2182,6 +2230,13 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->vc_deccm = global_cursor_default;
vc->vc_decim = 0;
+ if (vc->vc_saved_screen != NULL) {
+ kfree(vc->vc_saved_screen);
+ vc->vc_saved_screen = NULL;
+ vc->vc_saved_rows = 0;
+ vc->vc_saved_cols = 0;
+ }
+
vt_reset_keyboard(vc->vc_num);
vc->vc_cursor_type = cur_default;
@@ -3135,12 +3190,11 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count)
if (in_interrupt())
return count;
- console_lock();
+ guard(console_lock)();
currcons = vc->vc_num;
if (!vc_cons_allocated(currcons)) {
/* could this happen? */
pr_warn_once("con_write: tty %d not allocated\n", currcons+1);
- console_unlock();
return 0;
}
@@ -3184,7 +3238,7 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count)
con_flush(vc, &draw);
console_conditional_schedule();
notify_update(vc);
- console_unlock();
+
return n;
}
@@ -3199,7 +3253,7 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count)
*/
static void console_callback(struct work_struct *ignored)
{
- console_lock();
+ guard(console_lock)();
if (want_console >= 0) {
if (want_console != fg_console &&
@@ -3228,8 +3282,6 @@ static void console_callback(struct work_struct *ignored)
blank_timer_expired = 0;
}
notify_update(vc_cons[fg_console].d);
-
- console_unlock();
}
int set_console(int nr)
@@ -3433,9 +3485,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
return -EPERM;
return paste_selection(tty);
case TIOCL_UNBLANKSCREEN:
- console_lock();
- unblank_screen();
- console_unlock();
+ scoped_guard(console_lock)
+ unblank_screen();
break;
case TIOCL_SELLOADLUT:
if (!capable(CAP_SYS_ADMIN))
@@ -3451,9 +3502,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
data = vt_get_shift_state();
return put_user(data, p);
case TIOCL_GETMOUSEREPORTING:
- console_lock(); /* May be overkill */
- data = mouse_reporting();
- console_unlock();
+ scoped_guard(console_lock) /* May be overkill */
+ data = mouse_reporting();
return put_user(data, p);
case TIOCL_SETVESABLANK:
return set_vesa_blanking(param);
@@ -3484,15 +3534,14 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
* Needs the console lock here. Note that lots of other calls
* need fixing before the lock is actually useful!
*/
- console_lock();
- scrollfront(vc_cons[fg_console].d, lines);
- console_unlock();
+ scoped_guard(console_lock)
+ scrollfront(vc_cons[fg_console].d, lines);
break;
case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
- console_lock();
- ignore_poke = 1;
- do_blank_screen(0);
- console_unlock();
+ scoped_guard(console_lock) {
+ ignore_poke = 1;
+ do_blank_screen(0);
+ }
break;
case TIOCL_BLANKEDSCREEN:
return console_blanked;
@@ -3582,9 +3631,8 @@ static void con_flush_chars(struct tty_struct *tty)
if (in_interrupt()) /* from flush_to_ldisc */
return;
- console_lock();
+ guard(console_lock)();
set_cursor(vc);
- console_unlock();
}
/*
@@ -3596,22 +3644,20 @@ static int con_install(struct tty_driver *driver, struct tty_struct *tty)
struct vc_data *vc;
int ret;
- console_lock();
+ guard(console_lock)();
ret = vc_allocate(currcons);
if (ret)
- goto unlock;
+ return ret;
vc = vc_cons[currcons].d;
/* Still being freed */
- if (vc->port.tty) {
- ret = -ERESTARTSYS;
- goto unlock;
- }
+ if (vc->port.tty)
+ return -ERESTARTSYS;
ret = tty_port_install(&vc->port, driver, tty);
if (ret)
- goto unlock;
+ return ret;
tty->driver_data = vc;
vc->port.tty = tty;
@@ -3625,9 +3671,8 @@ static int con_install(struct tty_driver *driver, struct tty_struct *tty)
tty->termios.c_iflag |= IUTF8;
else
tty->termios.c_iflag &= ~IUTF8;
-unlock:
- console_unlock();
- return ret;
+
+ return 0;
}
static int con_open(struct tty_struct *tty, struct file *filp)
@@ -3646,9 +3691,9 @@ static void con_shutdown(struct tty_struct *tty)
{
struct vc_data *vc = tty->driver_data;
BUG_ON(vc == NULL);
- console_lock();
+
+ guard(console_lock)();
vc->port.tty = NULL;
- console_unlock();
}
static void con_cleanup(struct tty_struct *tty)
@@ -4137,15 +4182,13 @@ static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
struct con_driver *con = dev_get_drvdata(dev);
int bind = simple_strtoul(buf, NULL, 0);
- console_lock();
+ guard(console_lock)();
if (bind)
vt_bind(con);
else
vt_unbind(con);
- console_unlock();
-
return count;
}
@@ -4155,9 +4198,8 @@ static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
struct con_driver *con = dev_get_drvdata(dev);
int bind;
- console_lock();
- bind = con_is_bound(con->con);
- console_unlock();
+ scoped_guard(console_lock)
+ bind = con_is_bound(con->con);
return sysfs_emit(buf, "%i\n", bind);
}
@@ -4429,7 +4471,7 @@ static void con_driver_unregister_callback(struct work_struct *ignored)
{
int i;
- console_lock();
+ guard(console_lock)();
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
struct con_driver *con_driver = ®istered_con_driver[i];
@@ -4454,8 +4496,6 @@ static void con_driver_unregister_callback(struct work_struct *ignored)
con_driver->first = 0;
con_driver->last = 0;
}
-
- console_unlock();
}
/*
@@ -4491,9 +4531,8 @@ EXPORT_SYMBOL_GPL(do_take_over_console);
*/
void give_up_console(const struct consw *csw)
{
- console_lock();
+ guard(console_lock)();
do_unregister_con_driver(csw);
- console_unlock();
}
EXPORT_SYMBOL(give_up_console);
@@ -4541,9 +4580,8 @@ static int set_vesa_blanking(u8 __user *mode_user)
if (get_user(mode, mode_user))
return -EFAULT;
- console_lock();
+ guard(console_lock)();
vesa_blank_mode = (mode <= VESA_BLANK_MAX) ? mode : VESA_NO_BLANKING;
- console_unlock();
return 0;
}
@@ -4729,7 +4767,7 @@ int con_set_cmap(unsigned char __user *arg)
if (copy_from_user(colormap, arg, sizeof(colormap)))
return -EFAULT;
- console_lock();
+ guard(console_lock)();
for (i = k = 0; i < 16; i++) {
default_red[i] = colormap[k++];
default_grn[i] = colormap[k++];
@@ -4745,7 +4783,6 @@ int con_set_cmap(unsigned char __user *arg)
}
set_palette(vc_cons[i].d);
}
- console_unlock();
return 0;
}
@@ -4755,13 +4792,12 @@ int con_get_cmap(unsigned char __user *arg)
int i, k;
unsigned char colormap[3*16];
- console_lock();
- for (i = k = 0; i < 16; i++) {
- colormap[k++] = default_red[i];
- colormap[k++] = default_grn[i];
- colormap[k++] = default_blu[i];
- }
- console_unlock();
+ scoped_guard(console_lock)
+ for (i = k = 0; i < 16; i++) {
+ colormap[k++] = default_red[i];
+ colormap[k++] = default_grn[i];
+ colormap[k++] = default_blu[i];
+ }
if (copy_to_user(arg, colormap, sizeof(colormap)))
return -EFAULT;
@@ -4801,62 +4837,54 @@ void reset_palette(struct vc_data *vc)
static int con_font_get(struct vc_data *vc, struct console_font_op *op)
{
struct console_font font;
- int rc = -EINVAL;
int c;
unsigned int vpitch = op->op == KD_FONT_OP_GET_TALL ? op->height : 32;
if (vpitch > max_font_height)
return -EINVAL;
+ void *font_data __free(kvfree) = NULL;
if (op->data) {
- font.data = kvzalloc(max_font_size, GFP_KERNEL);
+ font.data = font_data = kvzalloc(max_font_size, GFP_KERNEL);
if (!font.data)
return -ENOMEM;
} else
font.data = NULL;
- console_lock();
- if (vc->vc_mode != KD_TEXT)
- rc = -EINVAL;
- else if (vc->vc_sw->con_font_get)
- rc = vc->vc_sw->con_font_get(vc, &font, vpitch);
- else
- rc = -ENOSYS;
- console_unlock();
+ scoped_guard(console_lock) {
+ if (vc->vc_mode != KD_TEXT)
+ return -EINVAL;
+ if (!vc->vc_sw->con_font_get)
+ return -ENOSYS;
- if (rc)
- goto out;
+ int ret = vc->vc_sw->con_font_get(vc, &font, vpitch);
+ if (ret)
+ return ret;
+ }
c = (font.width+7)/8 * vpitch * font.charcount;
if (op->data && font.charcount > op->charcount)
- rc = -ENOSPC;
+ return -ENOSPC;
if (font.width > op->width || font.height > op->height)
- rc = -ENOSPC;
- if (rc)
- goto out;
+ return -ENOSPC;
op->height = font.height;
op->width = font.width;
op->charcount = font.charcount;
if (op->data && copy_to_user(op->data, font.data, c))
- rc = -EFAULT;
+ return -EFAULT;
-out:
- kvfree(font.data);
- return rc;
+ return 0;
}
static int con_font_set(struct vc_data *vc, const struct console_font_op *op)
{
struct console_font font;
- int rc = -EINVAL;
int size;
unsigned int vpitch = op->op == KD_FONT_OP_SET_TALL ? op->height : 32;
- if (vc->vc_mode != KD_TEXT)
- return -EINVAL;
if (!op->data)
return -EINVAL;
if (op->charcount > max_font_glyphs)
@@ -4870,7 +4898,7 @@ static int con_font_set(struct vc_data *vc, const struct console_font_op *op)
if (size > max_font_size)
return -ENOSPC;
- font.data = memdup_user(op->data, size);
+ void *font_data __free(kfree) = font.data = memdup_user(op->data, size);
if (IS_ERR(font.data))
return PTR_ERR(font.data);
@@ -4878,18 +4906,17 @@ static int con_font_set(struct vc_data *vc, const struct console_font_op *op)
font.width = op->width;
font.height = op->height;
- console_lock();
+ guard(console_lock)();
+
if (vc->vc_mode != KD_TEXT)
- rc = -EINVAL;
- else if (vc->vc_sw->con_font_set) {
- if (vc_is_sel(vc))
- clear_selection();
- rc = vc->vc_sw->con_font_set(vc, &font, vpitch, op->flags);
- } else
- rc = -ENOSYS;
- console_unlock();
- kfree(font.data);
- return rc;
+ return -EINVAL;
+ if (!vc->vc_sw->con_font_set)
+ return -ENOSYS;
+
+ if (vc_is_sel(vc))
+ clear_selection();
+
+ return vc->vc_sw->con_font_set(vc, &font, vpitch, op->flags);
}
static int con_font_default(struct vc_data *vc, struct console_font_op *op)
@@ -4897,8 +4924,6 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op)
struct console_font font = {.width = op->width, .height = op->height};
char name[MAX_FONT_NAME];
char *s = name;
- int rc;
-
if (!op->data)
s = NULL;
@@ -4907,23 +4932,23 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op)
else
name[MAX_FONT_NAME - 1] = 0;
- console_lock();
- if (vc->vc_mode != KD_TEXT) {
- console_unlock();
- return -EINVAL;
- }
- if (vc->vc_sw->con_font_default) {
+ scoped_guard(console_lock) {
+ if (vc->vc_mode != KD_TEXT)
+ return -EINVAL;
+ if (!vc->vc_sw->con_font_default)
+ return -ENOSYS;
+
if (vc_is_sel(vc))
clear_selection();
- rc = vc->vc_sw->con_font_default(vc, &font, s);
- } else
- rc = -ENOSYS;
- console_unlock();
- if (!rc) {
- op->width = font.width;
- op->height = font.height;
+ int ret = vc->vc_sw->con_font_default(vc, &font, s);
+ if (ret)
+ return ret;
}
- return rc;
+
+ op->width = font.width;
+ op->height = font.height;
+
+ return 0;
}
int con_font_op(struct vc_data *vc, struct console_font_op *op)
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 61342e0..28993a3 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -373,15 +373,13 @@ static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd,
break;
}
- case KDSETMODE:
+ case KDSETMODE: {
if (!perm)
return -EPERM;
- console_lock();
- ret = vt_kdsetmode(vc, arg);
- console_unlock();
- return ret;
-
+ guard(console_lock)();
+ return vt_kdsetmode(vc, arg);
+ }
case KDGETMODE:
return put_user(vc->vc_mode, (int __user *)arg);
@@ -601,23 +599,21 @@ static int vt_setactivate(struct vt_setactivate __user *sa)
vsa.console--;
vsa.console = array_index_nospec(vsa.console, MAX_NR_CONSOLES);
- console_lock();
- ret = vc_allocate(vsa.console);
- if (ret) {
- console_unlock();
- return ret;
- }
+ scoped_guard(console_lock) {
+ ret = vc_allocate(vsa.console);
+ if (ret)
+ return ret;
- /*
- * This is safe providing we don't drop the console sem between
- * vc_allocate and finishing referencing nvc.
- */
- nvc = vc_cons[vsa.console].d;
- nvc->vt_mode = vsa.mode;
- nvc->vt_mode.frsig = 0;
- put_pid(nvc->vt_pid);
- nvc->vt_pid = get_pid(task_pid(current));
- console_unlock();
+ /*
+ * This is safe providing we don't drop the console sem between
+ * vc_allocate and finishing referencing nvc.
+ */
+ nvc = vc_cons[vsa.console].d;
+ nvc->vt_mode = vsa.mode;
+ nvc->vt_mode.frsig = 0;
+ put_pid(nvc->vt_pid);
+ nvc->vt_pid = get_pid(task_pid(current));
+ }
/* Commence switch and lock */
/* Review set_console locks */
@@ -630,19 +626,18 @@ static int vt_setactivate(struct vt_setactivate __user *sa)
static int vt_disallocate(unsigned int vc_num)
{
struct vc_data *vc = NULL;
- int ret = 0;
- console_lock();
- if (vt_busy(vc_num))
- ret = -EBUSY;
- else if (vc_num)
- vc = vc_deallocate(vc_num);
- console_unlock();
+ scoped_guard(console_lock) {
+ if (vt_busy(vc_num))
+ return -EBUSY;
+ if (vc_num)
+ vc = vc_deallocate(vc_num);
+ }
if (vc && vc_num >= MIN_NR_CONSOLES)
tty_port_put(&vc->port);
- return ret;
+ return 0;
}
/* deallocate all unused consoles, but leave 0 */
@@ -651,13 +646,12 @@ static void vt_disallocate_all(void)
struct vc_data *vc[MAX_NR_CONSOLES];
int i;
- console_lock();
- for (i = 1; i < MAX_NR_CONSOLES; i++)
- if (!vt_busy(i))
- vc[i] = vc_deallocate(i);
- else
- vc[i] = NULL;
- console_unlock();
+ scoped_guard(console_lock)
+ for (i = 1; i < MAX_NR_CONSOLES; i++)
+ if (!vt_busy(i))
+ vc[i] = vc_deallocate(i);
+ else
+ vc[i] = NULL;
for (i = 1; i < MAX_NR_CONSOLES; i++) {
if (vc[i] && i >= MIN_NR_CONSOLES)
@@ -703,7 +697,7 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs)
if (!vc_cons[i].d)
continue;
- console_lock();
+ guard(console_lock)();
vcp = vc_cons[i].d;
if (vcp) {
int ret;
@@ -718,11 +712,9 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs)
if (ret) {
vcp->vc_scan_lines = save_scan_lines;
vcp->vc_cell_height = save_cell_height;
- console_unlock();
return ret;
}
}
- console_unlock();
}
return 0;
@@ -770,7 +762,7 @@ int vt_ioctl(struct tty_struct *tty,
if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS)
return -EINVAL;
- console_lock();
+ guard(console_lock)();
vc->vt_mode = tmp;
/* the frsig is ignored, so we set it to 0 */
vc->vt_mode.frsig = 0;
@@ -778,7 +770,6 @@ int vt_ioctl(struct tty_struct *tty,
vc->vt_pid = get_pid(task_pid(current));
/* no switch is required -- saw@shade.msu.ru */
vc->vt_newvt = -1;
- console_unlock();
break;
}
@@ -787,9 +778,8 @@ int vt_ioctl(struct tty_struct *tty,
struct vt_mode tmp;
int rc;
- console_lock();
- memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
- console_unlock();
+ scoped_guard(console_lock)
+ memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
if (rc)
@@ -811,12 +801,10 @@ int vt_ioctl(struct tty_struct *tty,
return -EFAULT;
state = 1; /* /dev/tty0 is always open */
- console_lock(); /* required by vt_in_use() */
- for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
- ++i, mask <<= 1)
- if (vt_in_use(i))
- state |= mask;
- console_unlock();
+ scoped_guard(console_lock) /* required by vt_in_use() */
+ for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
+ if (vt_in_use(i))
+ state |= mask;
return put_user(state, &vtstat->v_state);
}
@@ -824,11 +812,10 @@ int vt_ioctl(struct tty_struct *tty,
* Returns the first available (non-opened) console.
*/
case VT_OPENQRY:
- console_lock(); /* required by vt_in_use() */
- for (i = 0; i < MAX_NR_CONSOLES; ++i)
- if (!vt_in_use(i))
- break;
- console_unlock();
+ scoped_guard(console_lock) /* required by vt_in_use() */
+ for (i = 0; i < MAX_NR_CONSOLES; ++i)
+ if (!vt_in_use(i))
+ break;
i = i < MAX_NR_CONSOLES ? (i+1) : -1;
return put_user(i, (int __user *)arg);
@@ -845,11 +832,11 @@ int vt_ioctl(struct tty_struct *tty,
arg--;
arg = array_index_nospec(arg, MAX_NR_CONSOLES);
- console_lock();
- ret = vc_allocate(arg);
- console_unlock();
- if (ret)
- return ret;
+ scoped_guard(console_lock) {
+ ret = vc_allocate(arg);
+ if (ret)
+ return ret;
+ }
set_console(arg);
break;
@@ -880,15 +867,13 @@ int vt_ioctl(struct tty_struct *tty,
* 2: completed switch-to OK
*/
case VT_RELDISP:
+ {
if (!perm)
return -EPERM;
- console_lock();
- ret = vt_reldisp(vc, arg);
- console_unlock();
-
- return ret;
-
+ guard(console_lock)();
+ return vt_reldisp(vc, arg);
+ }
/*
* Disallocate memory associated to VT (but leave VT1)
@@ -917,16 +902,17 @@ int vt_ioctl(struct tty_struct *tty,
get_user(cc, &vtsizes->v_cols))
return -EFAULT;
- console_lock();
+ guard(console_lock)();
for (i = 0; i < MAX_NR_CONSOLES; i++) {
vc = vc_cons[i].d;
if (vc) {
/* FIXME: review v tty lock */
- __vc_resize(vc_cons[i].d, cc, ll, true);
+ ret = __vc_resize(vc_cons[i].d, cc, ll, true);
+ if (ret)
+ return ret;
}
}
- console_unlock();
break;
}
@@ -996,20 +982,17 @@ void vc_SAK(struct work_struct *work)
struct vc_data *vc;
struct tty_struct *tty;
- console_lock();
+ guard(console_lock)();
vc = vc_con->d;
- if (vc) {
- /* FIXME: review tty ref counting */
- tty = vc->port.tty;
- /*
- * SAK should also work in all raw modes and reset
- * them properly.
- */
- if (tty)
- __do_SAK(tty);
- reset_vc(vc);
- }
- console_unlock();
+ if (!vc)
+ return;
+
+ /* FIXME: review tty ref counting */
+ tty = vc->port.tty;
+ /* SAK should also work in all raw modes and reset them properly. */
+ if (tty)
+ __do_SAK(tty);
+ reset_vc(vc);
}
#ifdef CONFIG_COMPAT
@@ -1287,31 +1270,29 @@ int vt_move_to_console(unsigned int vt, int alloc)
{
int prev;
- console_lock();
- /* Graphics mode - up to X */
- if (disable_vt_switch) {
- console_unlock();
- return 0;
- }
- prev = fg_console;
+ scoped_guard(console_lock) {
+ /* Graphics mode - up to X */
+ if (disable_vt_switch)
+ return 0;
- if (alloc && vc_allocate(vt)) {
- /* we can't have a free VC for now. Too bad,
- * we don't want to mess the screen for now. */
- console_unlock();
- return -ENOSPC;
- }
+ prev = fg_console;
- if (set_console(vt)) {
- /*
- * We're unable to switch to the SUSPEND_CONSOLE.
- * Let the calling function know so it can decide
- * what to do.
- */
- console_unlock();
- return -EIO;
+ if (alloc && vc_allocate(vt)) {
+ /*
+ * We can't have a free VC for now. Too bad, we don't want to mess the
+ * screen for now.
+ */
+ return -ENOSPC;
+ }
+
+ if (set_console(vt)) {
+ /*
+ * We're unable to switch to the SUSPEND_CONSOLE. Let the calling function
+ * know so it can decide what to do.
+ */
+ return -EIO;
+ }
}
- console_unlock();
if (vt_waitactive(vt + 1)) {
pr_debug("Suspend: Can't switch VCs.");
return -EINTR;
@@ -1328,8 +1309,7 @@ int vt_move_to_console(unsigned int vt, int alloc)
*/
void pm_set_vt_switch(int do_switch)
{
- console_lock();
+ guard(console_lock)();
disable_vt_switch = !do_switch;
- console_unlock();
}
EXPORT_SYMBOL(pm_set_vt_switch);
diff --git a/include/linux/console.h b/include/linux/console.h
index 8f10d0a..031a58d 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -666,6 +666,8 @@ void vcs_remove_sysfs(int index);
*/
extern atomic_t ignore_console_lock_warning;
+DEFINE_LOCK_GUARD_0(console_lock, console_lock(), console_unlock());
+
extern void console_init(void);
/* For deferred console takeover */
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index 59b4fec..13b3563 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -159,6 +159,9 @@ struct vc_data {
struct uni_pagedict *uni_pagedict;
struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */
u32 **vc_uni_lines; /* unicode screen content */
+ u16 *vc_saved_screen;
+ unsigned int vc_saved_cols;
+ unsigned int vc_saved_rows;
/* additional information is in vt_kern.h */
};
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 84b4648..666430b 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -788,6 +788,19 @@ static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned lo
spin_unlock_irqrestore(&up->lock, flags);
}
+DEFINE_GUARD(uart_port_lock, struct uart_port *, uart_port_lock(_T), uart_port_unlock(_T));
+DEFINE_GUARD_COND(uart_port_lock, _try, uart_port_trylock(_T));
+
+DEFINE_GUARD(uart_port_lock_irq, struct uart_port *, uart_port_lock_irq(_T),
+ uart_port_unlock_irq(_T));
+
+DEFINE_LOCK_GUARD_1(uart_port_lock_irqsave, struct uart_port,
+ uart_port_lock_irqsave(_T->lock, &_T->flags),
+ uart_port_unlock_irqrestore(_T->lock, _T->flags),
+ unsigned long flags);
+DEFINE_LOCK_GUARD_1_COND(uart_port_lock_irqsave, _try,
+ uart_port_trylock_irqsave(_T->lock, &_T->flags));
+
static inline int serial_port_in(struct uart_port *up, int offset)
{
return up->serial_in(up, offset);
diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h
index 332ddb9..660c254 100644
--- a/include/linux/tty_port.h
+++ b/include/linux/tty_port.h
@@ -270,4 +270,18 @@ static inline void tty_port_tty_vhangup(struct tty_port *port)
__tty_port_tty_hangup(port, false, false);
}
+#ifdef CONFIG_TTY
+void tty_kref_put(struct tty_struct *tty);
+__DEFINE_CLASS_IS_CONDITIONAL(tty_port_tty, true);
+__DEFINE_UNLOCK_GUARD(tty_port_tty, struct tty_struct, tty_kref_put(_T->lock));
+static inline class_tty_port_tty_t class_tty_port_tty_constructor(struct tty_port *tport)
+{
+ class_tty_port_tty_t _t = {
+ .lock = tty_port_tty_get(tport),
+ };
+ return _t;
+}
+#define scoped_tty() ((struct tty_struct *)(__guard_ptr(tty_port_tty)(&scope)))
+#endif
+
#endif