diff options
author | Peter Zijlstra <peterz@infradead.org> | 2020-11-26 13:16:55 +0100 |
---|---|---|
committer | Peter Zijlstra <peterz@infradead.org> | 2020-11-26 13:16:55 +0100 |
commit | 20c7775aecea04d8ca322039969d49dcf568e0e9 (patch) | |
tree | 138c057839197c9021043353e994815c0250e669 /drivers/tty | |
parent | perf/x86/intel: Add event constraint for CYCLE_ACTIVITY.STALLS_MEM_ANY (diff) | |
parent | Merge tag 'media/v5.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media (diff) | |
download | linux-dev-20c7775aecea04d8ca322039969d49dcf568e0e9.tar.xz linux-dev-20c7775aecea04d8ca322039969d49dcf568e0e9.zip |
Merge remote-tracking branch 'origin/master' into perf/core
Further perf/core patches will depend on:
d3f7b1bb2040 ("mm/gup: fix gup_fast with dynamic page table folding")
which is already in Linus' tree.
Diffstat (limited to 'drivers/tty')
72 files changed, 1214 insertions, 906 deletions
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig index d1b27b0522a3..8d60e0ff67b4 100644 --- a/drivers/tty/hvc/Kconfig +++ b/drivers/tty/hvc/Kconfig @@ -81,6 +81,7 @@ config HVC_DCC bool "ARM JTAG DCC console" depends on ARM || ARM64 select HVC_DRIVER + select SERIAL_CORE_CONSOLE help This console uses the JTAG DCC on ARM to create a console under the HVC driver. This console is used through a JTAG only on ARM. If you don't have diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 2a0e51a20e34..92c9a476defc 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -492,7 +492,7 @@ static void xencons_backend_changed(struct xenbus_device *dev, case XenbusStateClosed: if (dev->state == XenbusStateClosed) break; - /* fall through - Missed the backend's CLOSING state. */ + fallthrough; /* Missed the backend's CLOSING state */ case XenbusStateClosing: xenbus_frontend_closed(dev); break; diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 55105ac38f89..509d1042825a 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1216,13 +1216,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) tty_wait_until_sent(tty, HVCS_CLOSE_WAIT); - /* - * This line is important because it tells hvcs_open that this - * device needs to be re-configured the next time hvcs_open is - * called. - */ - tty->driver_data = NULL; - free_irq(irq, hvcsd); return; } else if (hvcsd->port.count < 0) { @@ -1237,6 +1230,13 @@ static void hvcs_cleanup(struct tty_struct * tty) { struct hvcs_struct *hvcsd = tty->driver_data; + /* + * This line is important because it tells hvcs_open that this + * device needs to be re-configured the next time hvcs_open is + * called. + */ + tty->driver_data = NULL; + tty_port_put(&hvcsd->port); } diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c index 6bbf35682d53..f5d3e68f5750 100644 --- a/drivers/tty/ipwireless/hardware.c +++ b/drivers/tty/ipwireless/hardware.c @@ -1006,9 +1006,9 @@ static int send_pending_packet(struct ipw_hardware *hw, int priority_limit) /* * Send and receive all queued packets. */ -static void ipwireless_do_tasklet(unsigned long hw_) +static void ipwireless_do_tasklet(struct tasklet_struct *t) { - struct ipw_hardware *hw = (struct ipw_hardware *) hw_; + struct ipw_hardware *hw = from_tasklet(hw, t, tasklet); unsigned long flags; spin_lock_irqsave(&hw->lock, flags); @@ -1635,7 +1635,7 @@ struct ipw_hardware *ipwireless_hardware_create(void) INIT_LIST_HEAD(&hw->rx_queue); INIT_LIST_HEAD(&hw->rx_pool); spin_lock_init(&hw->lock); - tasklet_init(&hw->tasklet, ipwireless_do_tasklet, (unsigned long) hw); + tasklet_setup(&hw->tasklet, ipwireless_do_tasklet); INIT_WORK(&hw->work_rx, ipw_receive_data_work); timer_setup(&hw->setup_timer, ipwireless_setup_timer, 0); diff --git a/drivers/tty/ipwireless/network.c b/drivers/tty/ipwireless/network.c index cf20616340a1..fe569f6294a2 100644 --- a/drivers/tty/ipwireless/network.c +++ b/drivers/tty/ipwireless/network.c @@ -117,7 +117,7 @@ static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel, skb->len, notify_packet_sent, network); - if (ret == -1) { + if (ret < 0) { skb_pull(skb, 2); return 0; } @@ -134,7 +134,7 @@ static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel, notify_packet_sent, network); kfree(buf); - if (ret == -1) + if (ret < 0) return 0; } kfree_skb(skb); diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index fad3401e604d..23584769fc29 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -218,7 +218,7 @@ static int ipw_write(struct tty_struct *linux_tty, ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS, buf, count, ipw_write_packet_sent_callback, tty); - if (ret == -1) { + if (ret < 0) { mutex_unlock(&tty->ipw_tty_mutex); return 0; } diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index 21e76a2ec182..a8e19b4833bf 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -243,7 +243,7 @@ done: /* Fall back to a 3 byte encoding */ word.bytes = 3; word.word &= 0x00ffffff; - /* Fall through */ + fallthrough; case 3: /* 3 byte encoding */ word.word |= 0x82000000; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 0a29a94ec438..25f3152089c2 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -76,10 +76,9 @@ module_param(debug, int, 0600); /** * struct gsm_mux_net - network interface - * @struct gsm_dlci* dlci * * Created when net interface is initialized. - **/ + */ struct gsm_mux_net { struct kref ref; struct gsm_dlci *dlci; @@ -222,11 +221,8 @@ struct gsm_mux { u8 received_fcs; u8 *txframe; /* TX framing buffer */ - /* Methods for the receiver side */ + /* Method for the receiver side */ void (*receive)(struct gsm_mux *gsm, u8 ch); - void (*error)(struct gsm_mux *gsm, u8 ch, u8 flag); - /* And transmit side */ - int (*output)(struct gsm_mux *mux, u8 *data, int len); /* Link Layer */ unsigned int mru; @@ -366,6 +362,8 @@ static const u8 gsm_fcs8[256] = { #define INIT_FCS 0xFF #define GOOD_FCS 0xCF +static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len); + /** * gsm_fcs_add - update FCS * @fcs: Current FCS @@ -400,7 +398,7 @@ static inline u8 gsm_fcs_add_block(u8 fcs, u8 *c, int len) /** * gsm_read_ea - read a byte into an EA * @val: variable holding value - * c: byte going into the EA + * @c: byte going into the EA * * Processes one byte of an EA. Updates the passed variable * and returns 1 if the EA is now completely read @@ -514,8 +512,8 @@ static void gsm_print_packet(const char *hdr, int addr, int cr, /** * gsm_stuff_packet - bytestuff a packet - * @ibuf: input - * @obuf: output + * @input: input buffer + * @output: output buffer * @len: length of input * * Expand a buffer by bytestuffing it. The worst case size change @@ -587,7 +585,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) WARN_ON(1); return; } - gsm->output(gsm, cbuf, len); + gsmld_output(gsm, cbuf, len); gsm_print_packet("-->", addr, cr, control, NULL, 0); } @@ -687,7 +685,7 @@ static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci) print_hex_dump_bytes("gsm_data_kick: ", DUMP_PREFIX_OFFSET, gsm->txframe, len); - if (gsm->output(gsm, gsm->txframe, len) < 0) + if (gsmld_output(gsm, gsm->txframe, len) < 0) break; /* FIXME: Can eliminate one SOF in many more cases */ gsm->tx_bytes -= msg->len; @@ -1305,7 +1303,7 @@ static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl) /** * gsm_control_retransmit - retransmit a control frame - * @data: pointer to our gsm object + * @t: timer contained in our gsm object * * Called off the T2 timer expiry in order to retransmit control frames * that have been lost in the system somewhere. The control_lock protects @@ -1342,7 +1340,7 @@ static void gsm_control_retransmit(struct timer_list *t) * @gsm: the GSM channel * @command: command to send including CR bit * @data: bytes of data (must be kmalloced) - * @len: length of the block to send + * @clen: length of the block to send * * Queue and dispatch a control command. Only one command can be * active at a time. In theory more can be outstanding but the matching @@ -1454,7 +1452,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) /** * gsm_dlci_t1 - T1 timer expiry - * @dlci: DLCI that opened + * @t: timer contained in the DLCI that opened * * The T1 timer handles retransmits of control frames (essentially of * SABM and DISC). We resend the command until the retry count runs out @@ -1550,7 +1548,7 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci) * gsm_dlci_data - data arrived * @dlci: channel * @data: block of bytes received - * @len: length of received block + * @clen: length of received block * * A UI or UIH frame has arrived which contains data for a channel * other than the control channel. If the relevant virtual tty is @@ -1584,7 +1582,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen) gsm_process_modem(tty, dlci, modem, clen); tty_kref_put(tty); } - /* Fall through */ + fallthrough; case 1: /* Line state will go via DLCI 0 controls only */ default: tty_insert_flip_string(port, data, len); @@ -1672,7 +1670,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr) /** * gsm_dlci_free - free DLCI - * @dlci: DLCI to free + * @port: tty port for DLCI to free * * Free up a DLCI. * @@ -1986,7 +1984,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) gsm->address = 0; gsm->state = GSM_ADDRESS; gsm->fcs = INIT_FCS; - /* Fall through */ + fallthrough; case GSM_ADDRESS: /* Address continuation */ gsm->fcs = gsm_fcs_add(gsm->fcs, c); if (gsm_read_ea(&gsm->address, c)) @@ -2128,7 +2126,6 @@ static int gsm_activate_mux(struct gsm_mux *gsm) gsm->receive = gsm0_receive; else gsm->receive = gsm1_receive; - gsm->error = gsm_error; spin_lock(&gsm_mux_lock); for (i = 0; i < MAX_MUX; i++) { @@ -2151,7 +2148,7 @@ static int gsm_activate_mux(struct gsm_mux *gsm) /** * gsm_free_mux - free up a mux - * @mux: mux to free + * @gsm: mux to free * * Dispose of allocated resources for a dead mux */ @@ -2164,7 +2161,7 @@ static void gsm_free_mux(struct gsm_mux *gsm) /** * gsm_free_muxr - free up a mux - * @mux: mux to free + * @ref: kreference to the mux to free * * Dispose of allocated resources for a dead mux */ @@ -2378,7 +2375,6 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) int ret, i; gsm->tty = tty_kref_get(tty); - gsm->output = gsmld_output; ret = gsm_activate_mux(gsm); if (ret != 0) tty_kref_put(gsm->tty); @@ -2438,7 +2434,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, case TTY_BREAK: case TTY_PARITY: case TTY_FRAME: - gsm->error(gsm, *dp, flags); + gsm_error(gsm, *dp, flags); break; default: WARN_ONCE(1, "%s: unknown flag %d\n", diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index b09eac4b6d64..12557ee1edb6 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -123,13 +123,13 @@ struct n_hdlc_buf_list { /** * struct n_hdlc - per device instance data structure - * @magic - magic value for structure - * @tbusy - reentrancy flag for tx wakeup code - * @woke_up - tx wakeup needs to be run again as it was called while @tbusy - * @tx_buf_list - list of pending transmit frame buffers - * @rx_buf_list - list of received frame buffers - * @tx_free_buf_list - list unused transmit frame buffers - * @rx_free_buf_list - list unused received frame buffers + * @magic: magic value for structure + * @tbusy: reentrancy flag for tx wakeup code + * @woke_up: tx wakeup needs to be run again as it was called while @tbusy + * @tx_buf_list: list of pending transmit frame buffers + * @rx_buf_list: list of received frame buffers + * @tx_free_buf_list: list unused transmit frame buffers + * @rx_free_buf_list: list unused received frame buffers */ struct n_hdlc { int magic; @@ -187,7 +187,7 @@ static void n_hdlc_free_buf_list(struct n_hdlc_buf_list *list) /** * n_hdlc_tty_close - line discipline close - * @tty - pointer to tty info structure + * @tty: pointer to tty info structure * * Called when the line discipline is changed to something * else, the tty is closed, or the tty detects a hangup. @@ -218,7 +218,7 @@ static void n_hdlc_tty_close(struct tty_struct *tty) /** * n_hdlc_tty_open - called when line discipline changed to n_hdlc - * @tty - pointer to tty info structure + * @tty: pointer to tty info structure * * Returns 0 if success, otherwise error code */ @@ -255,8 +255,8 @@ static int n_hdlc_tty_open(struct tty_struct *tty) /** * n_hdlc_send_frames - send frames on pending send buffer list - * @n_hdlc - pointer to ldisc instance data - * @tty - pointer to tty instance data + * @n_hdlc: pointer to ldisc instance data + * @tty: pointer to tty instance data * * Send frames on pending send buffer list until the driver does not accept a * frame (busy) this function is called after adding a frame to the send buffer @@ -335,7 +335,7 @@ check_again: /** * n_hdlc_tty_wakeup - Callback for transmit wakeup - * @tty - pointer to associated tty instance data + * @tty: pointer to associated tty instance data * * Called when low level device driver can accept more send data. */ @@ -348,10 +348,10 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty) /** * n_hdlc_tty_receive - Called by tty driver when receive data is available - * @tty - pointer to tty instance data - * @data - pointer to received data - * @flags - pointer to flags for data - * @count - count of received data in bytes + * @tty: pointer to tty instance data + * @data: pointer to received data + * @flags: pointer to flags for data + * @count: count of received data in bytes * * Called by tty low level driver when receive data is available. Data is * interpreted as one HDLC frame. @@ -408,10 +408,10 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, /** * n_hdlc_tty_read - Called to retrieve one frame of data (if available) - * @tty - pointer to tty instance data - * @file - pointer to open file object - * @buf - pointer to returned data buffer - * @nr - size of returned data buffer + * @tty: pointer to tty instance data + * @file: pointer to open file object + * @buf: pointer to returned data buffer + * @nr: size of returned data buffer * * Returns the number of bytes returned or error code. */ @@ -479,10 +479,10 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, /** * n_hdlc_tty_write - write a single frame of data to device - * @tty - pointer to associated tty device instance data - * @file - pointer to file object data - * @data - pointer to transmit data (one frame) - * @count - size of transmit frame in bytes + * @tty: pointer to associated tty device instance data + * @file: pointer to file object data + * @data: pointer to transmit data (one frame) + * @count: size of transmit frame in bytes * * Returns the number of bytes written (or error code). */ @@ -546,10 +546,10 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, /** * n_hdlc_tty_ioctl - process IOCTL system call for the tty device. - * @tty - pointer to tty instance data - * @file - pointer to open file object for device - * @cmd - IOCTL command code - * @arg - argument for IOCTL call (cmd dependent) + * @tty: pointer to tty instance data + * @file: pointer to open file object for device + * @cmd: IOCTL command code + * @arg: argument for IOCTL call (cmd dependent) * * Returns command dependent result. */ @@ -602,7 +602,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, case TCOFLUSH: flush_tx_queue(tty); } - /* fall through - to default */ + fallthrough; /* to default */ default: error = n_tty_ioctl_helper(tty, file, cmd, arg); @@ -614,9 +614,9 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, /** * n_hdlc_tty_poll - TTY callback for poll system call - * @tty - pointer to tty instance data - * @filp - pointer to open file object for device - * @poll_table - wait queue for operations + * @tty: pointer to tty instance data + * @filp: pointer to open file object for device + * @wait: wait queue for operations * * Determine which operations (read/write) will not block and return info * to caller. @@ -703,8 +703,8 @@ static struct n_hdlc *n_hdlc_alloc(void) /** * n_hdlc_buf_return - put the HDLC buffer after the head of the specified list - * @buf_list - pointer to the buffer list - * @buf - pointer to the buffer + * @buf_list: pointer to the buffer list + * @buf: pointer to the buffer */ static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list, struct n_hdlc_buf *buf) @@ -721,8 +721,8 @@ static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list, /** * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list - * @buf_list - pointer to buffer list - * @buf - pointer to buffer + * @buf_list: pointer to buffer list + * @buf: pointer to buffer */ static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list, struct n_hdlc_buf *buf) @@ -739,7 +739,7 @@ static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list, /** * n_hdlc_buf_get - remove and return an HDLC buffer from list - * @buf_list - pointer to HDLC buffer list + * @buf_list: pointer to HDLC buffer list * * Remove and return an HDLC buffer from the head of the specified HDLC buffer * list. diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index f75696f0ee2d..934dd2fb2ec8 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -605,7 +605,6 @@ static void receive_char(struct r3964_info *pInfo, const unsigned char c) } break; case R3964_WAIT_FOR_RX_REPEAT: - /* FALLTHROUGH */ case R3964_IDLE: if (c == STX) { /* Prevent rx_queue from overflow: */ diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 1794d84e7bf6..7e5e36315260 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -322,7 +322,7 @@ static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata) /** * reset_buffer_flags - reset buffer state - * @tty: terminal to reset + * @ldata: line disc data to reset * * Reset the read buffer counters and clear the flags. * Called from n_tty_open() and n_tty_flush_buffer(). @@ -906,7 +906,7 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab, /** * echo_char_raw - echo a character raw * @c: unicode byte to echo - * @tty: terminal device + * @ldata: line disc data * * Echo user input back onto the screen. This must be called only when * L_ECHO(tty) is true. Called from the driver receive_buf path. diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 00099a8439d2..23368cec7ee8 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -100,7 +100,7 @@ static void pty_unthrottle(struct tty_struct *tty) * pty_write - write to a pty * @tty: the tty we write from * @buf: kernel buffer of data - * @count: bytes to write + * @c: bytes to write * * Our "hardware" write method. Data is coming from the ldisc which * may be in a non sleeping state. We simply throw this at the other @@ -120,10 +120,10 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) spin_lock_irqsave(&to->port->lock, flags); /* Stuff the data into the input queue of the other end */ c = tty_insert_flip_string(to->port, buf, c); + spin_unlock_irqrestore(&to->port->lock, flags); /* And shovel */ if (c) tty_flip_buffer_push(to->port); - spin_unlock_irqrestore(&to->port->lock, flags); } return c; } diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c index 718e010fcb04..09baef4ccc39 100644 --- a/drivers/tty/serial/21285.c +++ b/drivers/tty/serial/21285.c @@ -50,25 +50,25 @@ static const char serial21285_name[] = "Footbridge UART"; static bool is_enabled(struct uart_port *port, int bit) { - unsigned long private_data = (unsigned long)port->private_data; + unsigned long *private_data = (unsigned long *)&port->private_data; - if (test_bit(bit, &private_data)) + if (test_bit(bit, private_data)) return true; return false; } static void enable(struct uart_port *port, int bit) { - unsigned long private_data = (unsigned long)port->private_data; + unsigned long *private_data = (unsigned long *)&port->private_data; - set_bit(bit, &private_data); + set_bit(bit, private_data); } static void disable(struct uart_port *port, int bit) { - unsigned long private_data = (unsigned long)port->private_data; + unsigned long *private_data = (unsigned long *)&port->private_data; - clear_bit(bit, &private_data); + clear_bit(bit, private_data); } #define is_tx_enabled(port) is_enabled(port, tx_enabled_bit) diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index 12d03e678295..fd95860cd661 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -110,12 +110,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) /* get the clock - this also enables the HW */ data->clk = devm_clk_get(&pdev->dev, NULL); - ret = PTR_ERR_OR_ZERO(data->clk); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "could not get clk: %d\n", ret); - return ret; - } + if (IS_ERR(data->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n"); /* get the interrupt */ ret = platform_get_irq(pdev, 0); @@ -155,9 +151,7 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) /* register the port */ ret = serial8250_register_8250_port(&up); if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "unable to register 8250 port - %d\n", ret); + dev_err_probe(&pdev->dev, ret, "unable to register 8250 port\n"); goto dis_clk; } data->line = ret; diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 87f450b7c177..9e204f9b799a 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -373,39 +373,6 @@ static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios) serial8250_do_set_ldisc(p, termios); } -static int dw8250_startup(struct uart_port *p) -{ - struct dw8250_data *d = to_dw8250_data(p->private_data); - int ret; - - /* - * Some platforms may provide a reference clock shared between several - * devices. In this case before using the serial port first we have to - * make sure that any clock state change is known to the UART port at - * least post factum. - */ - if (d->clk) { - ret = clk_notifier_register(d->clk, &d->clk_notifier); - if (ret) - dev_warn(p->dev, "Failed to set the clock notifier\n"); - } - - return serial8250_do_startup(p); -} - -static void dw8250_shutdown(struct uart_port *p) -{ - struct dw8250_data *d = to_dw8250_data(p->private_data); - - serial8250_do_shutdown(p); - - if (d->clk) { - clk_notifier_unregister(d->clk, &d->clk_notifier); - - flush_work(&d->clk_work); - } -} - /* * dw8250_fallback_dma_filter will prevent the UART from getting just any free * channel on platforms that have DMA engines, but don't have any channels @@ -501,8 +468,6 @@ static int dw8250_probe(struct platform_device *pdev) p->serial_out = dw8250_serial_out; p->set_ldisc = dw8250_set_ldisc; p->set_termios = dw8250_set_termios; - p->startup = dw8250_startup; - p->shutdown = dw8250_shutdown; p->membase = devm_ioremap(dev, regs->start, resource_size(regs)); if (!p->membase) @@ -622,6 +587,19 @@ static int dw8250_probe(struct platform_device *pdev) goto err_reset; } + /* + * Some platforms may provide a reference clock shared between several + * devices. In this case any clock state change must be known to the + * UART port at least post factum. + */ + if (data->clk) { + err = clk_notifier_register(data->clk, &data->clk_notifier); + if (err) + dev_warn(p->dev, "Failed to set the clock notifier\n"); + else + queue_work(system_unbound_wq, &data->clk_work); + } + platform_set_drvdata(pdev, data); pm_runtime_set_active(dev); @@ -648,6 +626,12 @@ static int dw8250_remove(struct platform_device *pdev) pm_runtime_get_sync(dev); + if (data->clk) { + clk_notifier_unregister(data->clk, &data->clk_notifier); + + flush_work(&data->clk_work); + } + serial8250_unregister_port(data->data.line); reset_control_assert(data->rst); diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index db88dee3a399..f8e99995eee9 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -39,7 +39,7 @@ static void serial8250_em_serial_out(struct uart_port *p, int offset, int value) break; case UART_IER: /* IER @ 0x04 */ value &= 0x0f; /* only 4 valid bits - not Xscale */ - /* fall-through */ + fallthrough; case UART_DLL_EM: /* DLL @ 0x24 (+9) */ case UART_DLM_EM: /* DLM @ 0x28 (+9) */ writel(value, p->membase + (offset << 2)); diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 04b9af7ed941..2d0e7c7e408d 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -744,6 +744,24 @@ static const struct exar8250_board pbn_exar_XR17V35x = { .exit = pci_xr17v35x_exit, }; +static const struct exar8250_board pbn_fastcom35x_2 = { + .num_ports = 2, + .setup = pci_xr17v35x_setup, + .exit = pci_xr17v35x_exit, +}; + +static const struct exar8250_board pbn_fastcom35x_4 = { + .num_ports = 4, + .setup = pci_xr17v35x_setup, + .exit = pci_xr17v35x_exit, +}; + +static const struct exar8250_board pbn_fastcom35x_8 = { + .num_ports = 8, + .setup = pci_xr17v35x_setup, + .exit = pci_xr17v35x_exit, +}; + static const struct exar8250_board pbn_exar_XR17V4358 = { .num_ports = 12, .setup = pci_xr17v35x_setup, @@ -811,9 +829,9 @@ static const struct pci_device_id exar_pci_tbl[] = { EXAR_DEVICE(EXAR, XR17V358, pbn_exar_XR17V35x), EXAR_DEVICE(EXAR, XR17V4358, pbn_exar_XR17V4358), EXAR_DEVICE(EXAR, XR17V8358, pbn_exar_XR17V8358), - EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_exar_XR17V35x), - EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_exar_XR17V35x), - EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_exar_XR17V35x), + EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_fastcom35x_2), + EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_fastcom35x_4), + EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_fastcom35x_8), EXAR_DEVICE(COMMTECH, 4222PCI335, pbn_fastcom335_2), EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4), diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index d1d253c4b518..31c9e83ea3cb 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -255,7 +255,7 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level) case CHIP_ID_F81866: sio_write_mask_reg(pdata, F81866_FIFO_CTRL, F81866_IRQ_MODE1, 0); - /* fall through */ + fallthrough; case CHIP_ID_F81865: sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_SHARE, F81866_IRQ_SHARE); diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index 0d0c80905c58..fbcc90c31ca1 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -1,15 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 -#include <linux/serial_reg.h> -#include <linux/serial_8250.h> - -#include "8250.h" - /* * Freescale 16550 UART "driver", Copyright (C) 2011 Paul Gortmaker. + * Copyright 2020 NXP + * Copyright 2020 Puresoftware Ltd. * * This isn't a full driver; it just provides an alternate IRQ - * handler to deal with an errata. Everything else is just - * using the bog standard 8250 support. + * handler to deal with an errata and provide ACPI wrapper. + * Everything else is just using the bog standard 8250 support. * * We follow code flow of serial8250_default_handle_irq() but add * a check for a break and insert a dummy read on the Rx for the @@ -20,6 +17,16 @@ * IRQ event to the next one. */ +#include <linux/acpi.h> +#include <linux/serial_reg.h> +#include <linux/serial_8250.h> + +#include "8250.h" + +struct fsl8250_data { + int line; +}; + int fsl8250_handle_irq(struct uart_port *port) { unsigned char lsr, orig_lsr; @@ -71,7 +78,7 @@ int fsl8250_handle_irq(struct uart_port *port) serial8250_modem_status(up); - if (lsr & UART_LSR_THRE) + if ((lsr & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) serial8250_tx_chars(up); up->lsr_saved_flags = orig_lsr; @@ -79,3 +86,90 @@ int fsl8250_handle_irq(struct uart_port *port) return 1; } EXPORT_SYMBOL_GPL(fsl8250_handle_irq); + +#ifdef CONFIG_ACPI +static int fsl8250_acpi_probe(struct platform_device *pdev) +{ + struct fsl8250_data *data; + struct uart_8250_port port8250; + struct device *dev = &pdev->dev; + struct resource *regs; + + int ret, irq; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(dev, "no registers defined\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + if (irq != -EPROBE_DEFER) + dev_err(dev, "cannot get irq\n"); + return irq; + } + + memset(&port8250, 0, sizeof(port8250)); + + ret = device_property_read_u32(dev, "clock-frequency", + &port8250.port.uartclk); + if (ret) + return ret; + + spin_lock_init(&port8250.port.lock); + + port8250.port.mapbase = regs->start; + port8250.port.irq = irq; + port8250.port.handle_irq = fsl8250_handle_irq; + port8250.port.type = PORT_16550A; + port8250.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF + | UPF_FIXED_PORT | UPF_IOREMAP + | UPF_FIXED_TYPE; + port8250.port.dev = dev; + port8250.port.mapsize = resource_size(regs); + port8250.port.iotype = UPIO_MEM; + port8250.port.irqflags = IRQF_SHARED; + + port8250.port.membase = devm_ioremap(dev, port8250.port.mapbase, + port8250.port.mapsize); + if (!port8250.port.membase) + return -ENOMEM; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->line = serial8250_register_8250_port(&port8250); + if (data->line < 0) + return data->line; + + platform_set_drvdata(pdev, data); + return 0; +} + +static int fsl8250_acpi_remove(struct platform_device *pdev) +{ + struct fsl8250_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); + return 0; +} + +static const struct acpi_device_id fsl_8250_acpi_id[] = { + { "NXP0018", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, fsl_8250_acpi_id); + +static struct platform_driver fsl8250_platform_driver = { + .driver = { + .name = "fsl-16550-uart", + .acpi_match_table = ACPI_PTR(fsl_8250_acpi_id), + }, + .probe = fsl8250_acpi_probe, + .remove = fsl8250_acpi_remove, +}; + +module_platform_driver(fsl8250_platform_driver); +#endif diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index dde766fa465f..988bf6bcce42 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -259,22 +259,14 @@ static int ingenic_uart_probe(struct platform_device *pdev) return -ENOMEM; data->clk_module = devm_clk_get(&pdev->dev, "module"); - if (IS_ERR(data->clk_module)) { - err = PTR_ERR(data->clk_module); - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, - "unable to get module clock: %d\n", err); - return err; - } + if (IS_ERR(data->clk_module)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->clk_module), + "unable to get module clock\n"); data->clk_baud = devm_clk_get(&pdev->dev, "baud"); - if (IS_ERR(data->clk_baud)) { - err = PTR_ERR(data->clk_baud); - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, - "unable to get baud clock: %d\n", err); - return err; - } + if (IS_ERR(data->clk_baud)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->clk_baud), + "unable to get baud clock\n"); err = clk_prepare_enable(data->clk_module); if (err) { diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 7b0dec14c8b8..fa876e2c13e5 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -317,7 +317,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, */ baud = tty_termios_baud_rate(termios); - serial8250_do_set_termios(port, termios, old); + serial8250_do_set_termios(port, termios, NULL); tty_termios_encode_baud_rate(termios, baud, baud); @@ -669,6 +669,7 @@ static int __init early_mtk8250_setup(struct earlycon_device *device, return -ENODEV; device->port.iotype = UPIO_MEM32; + device->port.regshift = 2; return early_serial8250_setup(device, NULL); } diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 1a74d511b02a..d5a513efb261 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -631,7 +631,7 @@ pci_timedia_setup(struct serial_private *priv, break; case 3: offset = board->uart_offset; - /* FALLTHROUGH */ + fallthrough; case 4: /* BAR 2 */ case 5: /* BAR 3 */ case 6: /* BAR 4 */ @@ -1776,6 +1776,39 @@ pci_wch_ch38x_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } + +#define CH384_XINT_ENABLE_REG 0xEB +#define CH384_XINT_ENABLE_BIT 0x02 + +static int pci_wch_ch38x_init(struct pci_dev *dev) +{ + int max_port; + unsigned long iobase; + + + switch (dev->device) { + case 0x3853: /* 8 ports */ + max_port = 8; + break; + default: + return -EINVAL; + } + + iobase = pci_resource_start(dev, 0); + outb(CH384_XINT_ENABLE_BIT, iobase + CH384_XINT_ENABLE_REG); + + return max_port; +} + +static void pci_wch_ch38x_exit(struct pci_dev *dev) +{ + unsigned long iobase; + + iobase = pci_resource_start(dev, 0); + outb(0x0, iobase + CH384_XINT_ENABLE_REG); +} + + static int pci_sunix_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1867,6 +1900,7 @@ pci_moxa_setup(struct serial_private *priv, #define PCIE_VENDOR_ID_WCH 0x1c00 #define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 #define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470 +#define PCIE_DEVICE_ID_WCH_CH384_8S 0x3853 #define PCIE_DEVICE_ID_WCH_CH382_2S 0x3253 #define PCI_VENDOR_ID_ACCESIO 0x494f @@ -2642,6 +2676,16 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_wch_ch38x_setup, }, + /* WCH CH384 8S card (16850 clone) */ + { + .vendor = PCIE_VENDOR_ID_WCH, + .device = PCIE_DEVICE_ID_WCH_CH384_8S, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_wch_ch38x_init, + .exit = pci_wch_ch38x_exit, + .setup = pci_wch_ch38x_setup, + }, /* * ASIX devices with FIFO bug */ @@ -2751,15 +2795,6 @@ static struct pci_serial_quirk *find_quirk(struct pci_dev *dev) return quirk; } -static inline int get_pci_irq(struct pci_dev *dev, - const struct pciserial_board *board) -{ - if (board->flags & FL_NOIRQ) - return 0; - else - return dev->irq; -} - /* * This is the configuration table for all of the PCI serial boards * which we support. It is directly indexed by the pci_board_num_t enum @@ -2913,6 +2948,7 @@ enum pci_board_num_t { pbn_fintek_F81512A, pbn_wch382_2, pbn_wch384_4, + pbn_wch384_8, pbn_pericom_PI7C9X7951, pbn_pericom_PI7C9X7952, pbn_pericom_PI7C9X7954, @@ -3650,6 +3686,13 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 8, .first_offset = 0xC0, }, + [pbn_wch384_8] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 115200, + .uart_offset = 8, + .first_offset = 0x00, + }, /* * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART */ @@ -5566,6 +5609,20 @@ static const struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_wch384_4 }, + { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_8S, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_wch384_8 }, + /* + * Realtek RealManage + */ + { PCI_VENDOR_ID_REALTEK, 0x816a, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_1_115200 }, + + { PCI_VENDOR_ID_REALTEK, 0x816b, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_1_115200 }, + /* Fintek PCI serial cards */ { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 09475695effd..b0af13074cd3 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1872,7 +1872,7 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) switch (iir & 0x3f) { case UART_IIR_RX_TIMEOUT: serial8250_rx_dma_flush(up); - /* fall-through */ + fallthrough; case UART_IIR_RLSI: return true; } @@ -2275,6 +2275,10 @@ int serial8250_do_startup(struct uart_port *port) if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) { unsigned char iir1; + + if (port->irqflags & IRQF_SHARED) + disable_irq_nosync(port->irq); + /* * Test for UARTs that do not reassert THRE when the * transmitter is idle and the interrupt has already @@ -2284,8 +2288,6 @@ int serial8250_do_startup(struct uart_port *port) * allow register changes to become visible. */ spin_lock_irqsave(&port->lock, flags); - if (up->port.irqflags & IRQF_SHARED) - disable_irq_nosync(port->irq); wait_for_xmitr(up, UART_LSR_THRE); serial_port_out_sync(port, UART_IER, UART_IER_THRI); @@ -2297,9 +2299,10 @@ int serial8250_do_startup(struct uart_port *port) iir = serial_port_in(port, UART_IIR); serial_port_out(port, UART_IER, 0); + spin_unlock_irqrestore(&port->lock, flags); + if (port->irqflags & IRQF_SHARED) enable_irq(port->irq); - spin_unlock_irqrestore(&port->lock, flags); /* * If the interrupt is not reasserted, or we otherwise @@ -2650,6 +2653,10 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) goto out_lock; port->uartclk = uartclk; + + if (!tty_port_initialized(&port->state->port)) + goto out_lock; + termios = &port->state->port.tty->termios; baud = serial8250_get_baud_rate(port, termios, NULL); @@ -2662,7 +2669,6 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) serial8250_set_divisor(port, baud, quot, frac); serial_port_out(port, UART_LCR, up->lcr); - serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS); spin_unlock_irqrestore(&port->lock, flags); serial8250_rpm_put(up); diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index e0b73a5402db..a2978abab0db 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -75,7 +75,7 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset) break; case UART_LCR: valshift = 8; - /* fall through */ + fallthrough; case UART_MCR: offset = UNIPHIER_UART_LCR_MCR; break; @@ -101,7 +101,7 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value) case UART_SCR: /* No SCR for this hardware. Use CHAR as a scratch register */ valshift = 8; - /* fall through */ + fallthrough; case UART_FCR: offset = UNIPHIER_UART_CHAR_FCR; break; @@ -109,7 +109,7 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value) valshift = 8; /* Divisor latch access bit does not exist. */ value &= ~UART_LCR_DLAB; - /* fall through */ + fallthrough; case UART_MCR: offset = UNIPHIER_UART_LCR_MCR; break; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 8a0352eb337c..28f22e58639c 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -8,6 +8,7 @@ menu "Serial drivers" config SERIAL_EARLYCON bool + depends on SERIAL_CORE help Support for early consoles with the earlycon parameter. This enables the console before standard serial driver is probed. The console is @@ -235,7 +236,7 @@ config SERIAL_CLPS711X_CONSOLE config SERIAL_SAMSUNG tristate "Samsung SoC serial support" - depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST + depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select SERIAL_CORE help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, @@ -517,8 +518,11 @@ config SERIAL_IMX_CONSOLE config SERIAL_IMX_EARLYCON bool "Earlycon on IMX serial port" + depends on ARCH_MXC || COMPILE_TEST depends on OF select SERIAL_EARLYCON + select SERIAL_CORE_CONSOLE + default y if SERIAL_IMX_CONSOLE help If you have enabled the earlycon on the Freescale IMX CPU you can make it the earlycon by answering Y to this option. diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index d056ee6cca33..caf167f0c10a 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_SERIAL_ZS) += zs.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o obj-$(CONFIG_SERIAL_CPM) += cpm_uart/ obj-$(CONFIG_SERIAL_IMX) += imx.o +obj-$(CONFIG_SERIAL_IMX_EARLYCON) += imx_earlycon.o obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o obj-$(CONFIG_SERIAL_ICOM) += icom.o obj-$(CONFIG_SERIAL_MESON) += meson_uart.o diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index c010f639298d..87dc3fc15694 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -308,8 +308,9 @@ static void pl011_write(unsigned int val, const struct uart_amba_port *uap, */ static int pl011_fifo_to_tty(struct uart_amba_port *uap) { - u16 status; unsigned int ch, flag, fifotaken; + int sysrq; + u16 status; for (fifotaken = 0; fifotaken != 256; fifotaken++) { status = pl011_read(uap, REG_FR); @@ -344,10 +345,12 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&uap->port, ch & 255)) - continue; + spin_unlock(&uap->port.lock); + sysrq = uart_handle_sysrq_char(&uap->port, ch & 255); + spin_lock(&uap->port.lock); - uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); + if (!sysrq) + uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); } return fifotaken; @@ -2241,9 +2244,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) clk_disable(uap->clk); } -static void __init -pl011_console_get_options(struct uart_amba_port *uap, int *baud, - int *parity, int *bits) +static void pl011_console_get_options(struct uart_amba_port *uap, int *baud, + int *parity, int *bits) { if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) { unsigned int lcr_h, ibrd, fbrd; @@ -2276,7 +2278,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, } } -static int __init pl011_console_setup(struct console *co, char *options) +static int pl011_console_setup(struct console *co, char *options) { struct uart_amba_port *uap; int baud = 38400; @@ -2344,8 +2346,8 @@ static int __init pl011_console_setup(struct console *co, char *options) * * Returns 0 if console matches; otherwise non-zero to use default matching */ -static int __init pl011_console_match(struct console *co, char *name, int idx, - char *options) +static int pl011_console_match(struct console *co, char *name, int idx, + char *options) { unsigned char iotype; resource_size_t addr; @@ -2615,7 +2617,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, static int pl011_register_port(struct uart_amba_port *uap) { - int ret; + int ret, i; /* Ensure interrupts from this UART are masked and cleared */ pl011_write(0, uap, REG_IMSC); @@ -2626,6 +2628,9 @@ static int pl011_register_port(struct uart_amba_port *uap) if (ret < 0) { dev_err(uap->port.dev, "Failed to register AMBA-PL011 driver\n"); + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) + if (amba_ports[i] == uap) + amba_ports[i] = NULL; return ret; } } diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 0c80a79d7442..c2be7cf91399 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -789,8 +789,10 @@ static int ar933x_uart_probe(struct platform_device *pdev) goto err_disable_clk; up->gpios = mctrl_gpio_init(port, 0); - if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS) - return PTR_ERR(up->gpios); + if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS) { + ret = PTR_ERR(up->gpios); + goto err_disable_clk; + } up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index e43471b33710..a24e5c2b30bc 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1722,10 +1722,11 @@ static int atmel_prepare_rx_pdc(struct uart_port *port) /* * tasklet handling tty stuff outside the interrupt handler. */ -static void atmel_tasklet_rx_func(unsigned long data) +static void atmel_tasklet_rx_func(struct tasklet_struct *t) { - struct uart_port *port = (struct uart_port *)data; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct atmel_uart_port *atmel_port = from_tasklet(atmel_port, t, + tasklet_rx); + struct uart_port *port = &atmel_port->uart; /* The interrupt handler does not take the lock */ spin_lock(&port->lock); @@ -1733,10 +1734,11 @@ static void atmel_tasklet_rx_func(unsigned long data) spin_unlock(&port->lock); } -static void atmel_tasklet_tx_func(unsigned long data) +static void atmel_tasklet_tx_func(struct tasklet_struct *t) { - struct uart_port *port = (struct uart_port *)data; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct atmel_uart_port *atmel_port = from_tasklet(atmel_port, t, + tasklet_tx); + struct uart_port *port = &atmel_port->uart; /* The interrupt handler does not take the lock */ spin_lock(&port->lock); @@ -1845,7 +1847,7 @@ static void atmel_get_ip_name(struct uart_port *port) version = atmel_uart_readl(port, ATMEL_US_VERSION); switch (version) { case 0x814: /* sama5d2 */ - /* fall through */ + fallthrough; case 0x701: /* sama5d4 */ atmel_port->fidi_min = 3; atmel_port->fidi_max = 65535; @@ -1911,10 +1913,8 @@ static int atmel_startup(struct uart_port *port) } atomic_set(&atmel_port->tasklet_shutdown, 0); - tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func, - (unsigned long)port); - tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func, - (unsigned long)port); + tasklet_setup(&atmel_port->tasklet_rx, atmel_tasklet_rx_func); + tasklet_setup(&atmel_port->tasklet_tx, atmel_tasklet_tx_func); /* * Initialize DMA (if necessary) diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 2ae9190b64bb..b70877932d47 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -56,7 +56,6 @@ static void __init earlycon_init(struct earlycon_device *device, const char *name) { struct console *earlycon = device->con; - struct uart_port *port = &device->port; const char *s; size_t len; @@ -70,6 +69,12 @@ static void __init earlycon_init(struct earlycon_device *device, len = s - name; strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name))); earlycon->data = &early_console_dev; +} + +static void __init earlycon_print_info(struct earlycon_device *device) +{ + struct console *earlycon = device->con; + struct uart_port *port = &device->port; if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 || port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE) @@ -140,6 +145,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match) earlycon_init(&early_console_dev, match->name); err = match->setup(&early_console_dev, buf); + earlycon_print_info(&early_console_dev); if (err < 0) return err; if (!early_console_dev.con->write) @@ -302,6 +308,7 @@ int __init of_setup_earlycon(const struct earlycon_id *match, } earlycon_init(&early_console_dev, match->name); err = match->setup(&early_console_dev, options); + earlycon_print_info(&early_console_dev); if (err < 0) return err; if (!early_console_dev.con->write) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 7ca642249224..bd047e1f9bea 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -314,9 +314,10 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids); /* Forward declare this for the dma callbacks*/ static void lpuart_dma_tx_complete(void *arg); -static inline bool is_ls1028a_lpuart(struct lpuart_port *sport) +static inline bool is_layerscape_lpuart(struct lpuart_port *sport) { - return sport->devtype == LS1028A_LPUART; + return (sport->devtype == LS1021A_LPUART || + sport->devtype == LS1028A_LPUART); } static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport) @@ -649,26 +650,24 @@ static int lpuart32_poll_init(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); /* Disable Rx & Tx */ - lpuart32_write(&sport->port, UARTCTRL, 0); + lpuart32_write(&sport->port, 0, UARTCTRL); temp = lpuart32_read(&sport->port, UARTFIFO); /* Enable Rx and Tx FIFO */ - lpuart32_write(&sport->port, UARTFIFO, - temp | UARTFIFO_RXFE | UARTFIFO_TXFE); + lpuart32_write(&sport->port, temp | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO); /* flush Tx and Rx FIFO */ - lpuart32_write(&sport->port, UARTFIFO, - UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH); + lpuart32_write(&sport->port, UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, UARTFIFO); /* explicitly clear RDRF */ if (lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_RDRF) { lpuart32_read(&sport->port, UARTDATA); - lpuart32_write(&sport->port, UARTFIFO, UARTFIFO_RXUF); + lpuart32_write(&sport->port, UARTFIFO_RXUF, UARTFIFO); } /* Enable Rx and Tx */ - lpuart32_write(&sport->port, UARTCTRL, UARTCTRL_RE | UARTCTRL_TE); + lpuart32_write(&sport->port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL); spin_unlock_irqrestore(&sport->port.lock, flags); return 0; @@ -677,12 +676,12 @@ static int lpuart32_poll_init(struct uart_port *port) static void lpuart32_poll_put_char(struct uart_port *port, unsigned char c) { lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TDRE); - lpuart32_write(port, UARTDATA, c); + lpuart32_write(port, c, UARTDATA); } static int lpuart32_poll_get_char(struct uart_port *port) { - if (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_RDRF)) + if (!(lpuart32_read(port, UARTWATER) >> UARTWATER_RXCNT_OFF)) return NO_POLL_CHAR; return lpuart32_read(port, UARTDATA); @@ -978,6 +977,15 @@ static irqreturn_t lpuart_int(int irq, void *dev_id) sts = readb(sport->port.membase + UARTSR1); + /* SysRq, using dma, check for linebreak by framing err. */ + if (sts & UARTSR1_FE && sport->lpuart_dma_rx_use) { + readb(sport->port.membase + UARTDR); + uart_handle_break(&sport->port); + /* linebreak produces some garbage, removing it */ + writeb(UARTCFIFO_RXFLUSH, sport->port.membase + UARTCFIFO); + return IRQ_HANDLED; + } + if (sts & UARTSR1_RDRF && !sport->lpuart_dma_rx_use) lpuart_rxint(sport); @@ -1006,6 +1014,37 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id) return IRQ_HANDLED; } + +static inline void lpuart_handle_sysrq_chars(struct uart_port *port, + unsigned char *p, int count) +{ + while (count--) { + if (*p && uart_handle_sysrq_char(port, *p)) + return; + p++; + } +} + +static void lpuart_handle_sysrq(struct lpuart_port *sport) +{ + struct circ_buf *ring = &sport->rx_ring; + int count; + + if (ring->head < ring->tail) { + count = sport->rx_sgl.length - ring->tail; + lpuart_handle_sysrq_chars(&sport->port, + ring->buf + ring->tail, count); + ring->tail = 0; + } + + if (ring->head > ring->tail) { + count = ring->head - ring->tail; + lpuart_handle_sysrq_chars(&sport->port, + ring->buf + ring->tail, count); + ring->tail = ring->head; + } +} + static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) { struct tty_port *port = &sport->port.state->port; @@ -1092,6 +1131,15 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) */ ring->head = sport->rx_sgl.length - state.residue; BUG_ON(ring->head > sport->rx_sgl.length); + + /* + * Silent handling of keys pressed in the sysrq timeframe + */ + if (sport->port.sysrq) { + lpuart_handle_sysrq(sport); + goto exit; + } + /* * At this point ring->head may point to the first byte right after the * last byte of the dma buffer: @@ -1123,6 +1171,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) sport->port.icount.rx += count; } +exit: dma_sync_sg_for_device(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); @@ -1260,7 +1309,7 @@ static int lpuart_config_rs485(struct uart_port *port, modem |= UARTMODEM_TXRTSE; /* - * RTS needs to be logic HIGH either during transer _or_ after + * RTS needs to be logic HIGH either during transfer _or_ after * transfer, other variants are not supported by the hardware. */ @@ -1311,7 +1360,7 @@ static int lpuart32_config_rs485(struct uart_port *port, modem |= UARTMODEM_TXRTSE; /* - * RTS needs to be logic HIGH either during transer _or_ after + * RTS needs to be logic HIGH either during transfer _or_ after * transfer, other variants are not supported by the hardware. */ @@ -1559,6 +1608,7 @@ err: static void lpuart_rx_dma_startup(struct lpuart_port *sport) { int ret; + unsigned char cr3; if (!sport->dma_rx_chan) goto err; @@ -1575,6 +1625,12 @@ static void lpuart_rx_dma_startup(struct lpuart_port *sport) sport->lpuart_dma_rx_use = true; rx_dma_timer_init(sport); + if (sport->port.has_sysrq) { + cr3 = readb(sport->port.membase + UARTCR3); + cr3 |= UARTCR3_FEIE; + writeb(cr3, sport->port.membase + UARTCR3); + } + return; err: @@ -1646,11 +1702,11 @@ static int lpuart32_startup(struct uart_port *port) UARTFIFO_FIFOSIZE_MASK); /* - * The LS1028A has a fixed length of 16 words. Although it supports the - * RX/TXSIZE fields their encoding is different. Eg the reference manual - * states 0b101 is 16 words. + * The LS1021A and LS1028A have a fixed FIFO depth of 16 words. + * Although they support the RX/TXSIZE fields, their encoding is + * different. Eg the reference manual states 0b101 is 16 words. */ - if (is_ls1028a_lpuart(sport)) { + if (is_layerscape_lpuart(sport)) { sport->rxfifo_size = 16; sport->txfifo_size = 16; sport->port.fifosize = sport->txfifo_size; diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index 624f3d541c68..94c8281ddb5f 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -138,24 +138,24 @@ static void free_port_memory(struct icom_port *icom_port) trace(icom_port, "RET_PORT_MEM", 0); if (icom_port->recv_buf) { - pci_free_consistent(dev, 4096, icom_port->recv_buf, - icom_port->recv_buf_pci); + dma_free_coherent(&dev->dev, 4096, icom_port->recv_buf, + icom_port->recv_buf_pci); icom_port->recv_buf = NULL; } if (icom_port->xmit_buf) { - pci_free_consistent(dev, 4096, icom_port->xmit_buf, - icom_port->xmit_buf_pci); + dma_free_coherent(&dev->dev, 4096, icom_port->xmit_buf, + icom_port->xmit_buf_pci); icom_port->xmit_buf = NULL; } if (icom_port->statStg) { - pci_free_consistent(dev, 4096, icom_port->statStg, - icom_port->statStg_pci); + dma_free_coherent(&dev->dev, 4096, icom_port->statStg, + icom_port->statStg_pci); icom_port->statStg = NULL; } if (icom_port->xmitRestart) { - pci_free_consistent(dev, 4096, icom_port->xmitRestart, - icom_port->xmitRestart_pci); + dma_free_coherent(&dev->dev, 4096, icom_port->xmitRestart, + icom_port->xmitRestart_pci); icom_port->xmitRestart = NULL; } } @@ -169,7 +169,8 @@ static int get_port_memory(struct icom_port *icom_port) struct pci_dev *dev = icom_port->adapter->pci_dev; icom_port->xmit_buf = - pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci); + dma_alloc_coherent(&dev->dev, 4096, &icom_port->xmit_buf_pci, + GFP_KERNEL); if (!icom_port->xmit_buf) { dev_err(&dev->dev, "Can not allocate Transmit buffer\n"); return -ENOMEM; @@ -179,7 +180,8 @@ static int get_port_memory(struct icom_port *icom_port) (unsigned long) icom_port->xmit_buf); icom_port->recv_buf = - pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci); + dma_alloc_coherent(&dev->dev, 4096, &icom_port->recv_buf_pci, + GFP_KERNEL); if (!icom_port->recv_buf) { dev_err(&dev->dev, "Can not allocate Receive buffer\n"); free_port_memory(icom_port); @@ -189,7 +191,8 @@ static int get_port_memory(struct icom_port *icom_port) (unsigned long) icom_port->recv_buf); icom_port->statStg = - pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci); + dma_alloc_coherent(&dev->dev, 4096, &icom_port->statStg_pci, + GFP_KERNEL); if (!icom_port->statStg) { dev_err(&dev->dev, "Can not allocate Status buffer\n"); free_port_memory(icom_port); @@ -199,7 +202,8 @@ static int get_port_memory(struct icom_port *icom_port) (unsigned long) icom_port->statStg); icom_port->xmitRestart = - pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci); + dma_alloc_coherent(&dev->dev, 4096, &icom_port->xmitRestart_pci, + GFP_KERNEL); if (!icom_port->xmitRestart) { dev_err(&dev->dev, "Can not allocate xmit Restart buffer\n"); @@ -414,7 +418,7 @@ static void load_code(struct icom_port *icom_port) /*Set up data in icom DRAM to indicate where personality *code is located and its length. */ - new_page = pci_alloc_consistent(dev, 4096, &temp_pci); + new_page = dma_alloc_coherent(&dev->dev, 4096, &temp_pci, GFP_KERNEL); if (!new_page) { dev_err(&dev->dev, "Can not allocate DMA buffer\n"); @@ -494,7 +498,7 @@ static void load_code(struct icom_port *icom_port) } if (new_page != NULL) - pci_free_consistent(dev, 4096, new_page, temp_pci); + dma_free_coherent(&dev->dev, 4096, new_page, temp_pci); } static int startup(struct icom_port *icom_port) diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 7d16fe41932f..21d519c804cb 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -257,7 +257,7 @@ static void mrdy_assert(struct ifx_spi_device *ifx_dev) /** * ifx_spi_timeout - SPI timeout - * @arg: our SPI device + * @t: timer in our SPI device * * The SPI has timed out: hang up the tty. Users will then see a hangup * and error events. @@ -277,7 +277,6 @@ static void ifx_spi_timeout(struct timer_list *t) /** * ifx_spi_tiocmget - get modem lines * @tty: our tty device - * @filp: file handle issuing the request * * Map the signal state into Linux modem flags and report the value * in Linux terms @@ -531,7 +530,7 @@ static int ifx_spi_chars_in_buffer(struct tty_struct *tty) /** * ifx_port_hangup - * @port: our tty port + * @tty: our tty * * tty port hang up. Called when tty_hangup processing is invoked either * by loss of carrier, or by software (eg vhangup). Serialized against @@ -611,7 +610,7 @@ static const struct tty_operations ifx_spi_serial_ops = { /** * ifx_spi_insert_fip_string - queue received data - * @ifx_ser: our SPI device + * @ifx_dev: our SPI device * @chars: buffer we have received * @size: number of chars reeived * @@ -725,10 +724,11 @@ complete_exit: * Queue data for transmission if possible and then kick off the * transfer. */ -static void ifx_spi_io(unsigned long data) +static void ifx_spi_io(struct tasklet_struct *t) { int retval; - struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data; + struct ifx_spi_device *ifx_dev = from_tasklet(ifx_dev, t, + io_work_tasklet); if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags) && test_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags)) { @@ -1067,8 +1067,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) init_waitqueue_head(&ifx_dev->mdm_reset_wait); spi_set_drvdata(spi, ifx_dev); - tasklet_init(&ifx_dev->io_work_tasklet, ifx_spi_io, - (unsigned long)ifx_dev); + tasklet_setup(&ifx_dev->io_work_tasklet, ifx_spi_io); set_bit(IFX_SPI_STATE_PRESENT, &ifx_dev->flags); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index ce8c472cf385..cacf7266a262 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -942,8 +942,14 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) struct imx_port *sport = dev_id; unsigned int usr1, usr2, ucr1, ucr2, ucr3, ucr4; irqreturn_t ret = IRQ_NONE; + unsigned long flags = 0; - spin_lock(&sport->port.lock); + /* + * IRQs might not be disabled upon entering this interrupt handler, + * e.g. when interrupt handlers are forced to be threaded. To support + * this scenario as well, disable IRQs when acquiring the spinlock. + */ + spin_lock_irqsave(&sport->port.lock, flags); usr1 = imx_uart_readl(sport, USR1); usr2 = imx_uart_readl(sport, USR2); @@ -1013,7 +1019,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) ret = IRQ_HANDLED; } - spin_unlock(&sport->port.lock); + spin_unlock_irqrestore(&sport->port.lock, flags); return ret; } @@ -1552,10 +1558,6 @@ static void imx_uart_shutdown(struct uart_port *port) ucr2 = imx_uart_readl(sport, UCR2); ucr2 &= ~(UCR2_TXEN | UCR2_ATEN); imx_uart_writel(sport, ucr2, UCR2); - - ucr4 = imx_uart_readl(sport, UCR4); - ucr4 &= ~UCR4_OREN; - imx_uart_writel(sport, ucr4, UCR4); spin_unlock_irqrestore(&sport->port.lock, flags); /* @@ -1568,10 +1570,15 @@ static void imx_uart_shutdown(struct uart_port *port) */ spin_lock_irqsave(&sport->port.lock, flags); + ucr1 = imx_uart_readl(sport, UCR1); ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN | UCR1_RXDMAEN | UCR1_ATDMAEN); - imx_uart_writel(sport, ucr1, UCR1); + + ucr4 = imx_uart_readl(sport, UCR4); + ucr4 &= ~(UCR4_OREN | UCR4_TCEN); + imx_uart_writel(sport, ucr4, UCR4); + spin_unlock_irqrestore(&sport->port.lock, flags); clk_disable_unprepare(sport->clk_per); @@ -2001,16 +2008,6 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) unsigned int ucr1; unsigned long flags = 0; int locked = 1; - int retval; - - retval = clk_enable(sport->clk_per); - if (retval) - return; - retval = clk_enable(sport->clk_ipg); - if (retval) { - clk_disable(sport->clk_per); - return; - } if (sport->port.sysrq) locked = 0; @@ -2046,9 +2043,6 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) if (locked) spin_unlock_irqrestore(&sport->port.lock, flags); - - clk_disable(sport->clk_ipg); - clk_disable(sport->clk_per); } /* @@ -2149,15 +2143,14 @@ imx_uart_console_setup(struct console *co, char *options) retval = uart_set_options(&sport->port, co, baud, parity, bits, flow); - clk_disable(sport->clk_ipg); if (retval) { - clk_unprepare(sport->clk_ipg); + clk_disable_unprepare(sport->clk_ipg); goto error_console; } - retval = clk_prepare(sport->clk_per); + retval = clk_prepare_enable(sport->clk_per); if (retval) - clk_unprepare(sport->clk_ipg); + clk_disable_unprepare(sport->clk_ipg); error_console: return retval; @@ -2389,8 +2382,7 @@ static int imx_uart_probe(struct platform_device *pdev) /* Disable interrupts before requesting them */ ucr1 = imx_uart_readl(sport, UCR1); - ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | - UCR1_TRDYEN | UCR1_RTSDEN); + ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | UCR1_RTSDEN); imx_uart_writel(sport, ucr1, UCR1); if (!imx_uart_is_imx1(sport) && sport->dte_mode) { diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 8434bd5a8ec7..21130af106bb 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1056,9 +1056,9 @@ static int max310x_startup(struct uart_port *port) max310x_port_update(port, MAX310X_MODE1_REG, MAX310X_MODE1_TRNSCVCTRL_BIT, 0); - /* Configure MODE2 register & Reset FIFOs*/ - val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT; - max310x_port_write(port, MAX310X_MODE2_REG, val); + /* Reset FIFOs */ + max310x_port_write(port, MAX310X_MODE2_REG, + MAX310X_MODE2_FIFORST_BIT); max310x_port_update(port, MAX310X_MODE2_REG, MAX310X_MODE2_FIFORST_BIT, 0); @@ -1086,8 +1086,27 @@ static int max310x_startup(struct uart_port *port) /* Clear IRQ status register */ max310x_port_read(port, MAX310X_IRQSTS_REG); - /* Enable RX, TX, CTS change interrupts */ - val = MAX310X_IRQ_RXEMPTY_BIT | MAX310X_IRQ_TXEMPTY_BIT; + /* + * Let's ask for an interrupt after a timeout equivalent to + * the receiving time of 4 characters after the last character + * has been received. + */ + max310x_port_write(port, MAX310X_RXTO_REG, 4); + + /* + * Make sure we also get RX interrupts when the RX FIFO is + * filling up quickly, so get an interrupt when half of the RX + * FIFO has been filled in. + */ + max310x_port_write(port, MAX310X_FIFOTRIGLVL_REG, + MAX310X_FIFOTRIGLVL_RX(MAX310X_FIFO_SIZE / 2)); + + /* Enable RX timeout interrupt in LSR */ + max310x_port_write(port, MAX310X_LSR_IRQEN_REG, + MAX310X_LSR_RXTO_BIT); + + /* Enable LSR, RX FIFO trigger, CTS change interrupts */ + val = MAX310X_IRQ_LSR_BIT | MAX310X_IRQ_RXFIFO_BIT | MAX310X_IRQ_TXEMPTY_BIT; max310x_port_write(port, MAX310X_IRQEN_REG, val | MAX310X_IRQ_CTS_BIT); return 0; diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 7dbfb4cde124..09c88c48fb7b 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -632,6 +632,7 @@ static int mcf_probe(struct platform_device *pdev) port->ops = &mcf_uart_ops; port->flags = UPF_BOOT_AUTOCONF; port->rs485_config = mcf_config_rs485; + port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MCF_CONSOLE); uart_add_one_port(&mcf_driver, port); } diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index 4f53a4caabf6..9acae5f8fc32 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c @@ -173,7 +173,7 @@ static void men_z135_reg_clr(struct men_z135_port *uart, /** * men_z135_handle_modem_status() - Handle change of modem status - * @port: The UART port + * @uart: The UART port * * Handle change of modem status register. This is done by reading the "delta" * versions of DCD (Data Carrier Detect) and CTS (Clear To Send). @@ -236,7 +236,7 @@ static u16 get_rx_fifo_content(struct men_z135_port *uart) /** * men_z135_handle_rx() - RX tasklet routine - * @arg: Pointer to struct men_z135_port + * @uart: Pointer to struct men_z135_port * * Copy from RX FIFO and acknowledge number of bytes copied. */ @@ -287,7 +287,7 @@ static void men_z135_handle_rx(struct men_z135_port *uart) /** * men_z135_handle_tx() - TX tasklet routine - * @arg: Pointer to struct men_z135_port + * @uart: Pointer to struct men_z135_port * */ static void men_z135_handle_tx(struct men_z135_port *uart) @@ -596,7 +596,7 @@ static void men_z135_stop_rx(struct uart_port *port) /** * men_z135_enable_ms() - Enable Modem Status - * port: + * @port: the port * * Enable Modem Status IRQ. */ diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 4e9a590712cb..118b29912289 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -803,7 +803,7 @@ static int mvebu_uart_probe(struct platform_device *pdev) &pdev->dev); struct uart_port *port; struct mvebu_uart *mvuart; - int ret, id, irq; + int id, irq; if (!reg) { dev_err(&pdev->dev, "no registers defined\n"); @@ -912,10 +912,7 @@ static int mvebu_uart_probe(struct platform_device *pdev) udelay(1); writel(0, port->membase + UART_CTRL(port)); - ret = uart_add_one_port(&mvebu_uart_driver, port); - if (ret) - return ret; - return 0; + return uart_add_one_port(&mvebu_uart_driver, port); } static struct mvebu_uart_driver_data uart_std_driver_data = { diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 8573fc9cb0cd..76b94d0ff586 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -587,7 +587,6 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) transmit_chars(up, lsr); break; case UART_IIR_RX_TIMEOUT: - /* FALLTHROUGH */ case UART_IIR_RDI: serial_omap_rdi(up, lsr); break; @@ -598,7 +597,6 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) /* simply try again */ break; case UART_IIR_XOFF: - /* FALLTHROUGH */ default: break; } diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 67aca8cb9cd4..a7363bc66c11 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -981,7 +981,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) priv->tx_dma_use = 1; - priv->sg_tx_p = kcalloc(num, sizeof(struct scatterlist), GFP_ATOMIC); + priv->sg_tx_p = kmalloc_array(num, sizeof(struct scatterlist), GFP_ATOMIC); if (!priv->sg_tx_p) { dev_err(priv->port.dev, "%s:kzalloc Failed\n", __func__); return 0; diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 96e7aa479961..063484b22523 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1644,7 +1644,7 @@ static int __init pmz_probe(void) * TODO: Add routines with proper locking to do that... */ node_a = node_b = NULL; - for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) { + for_each_child_of_node(node_p, np) { if (of_node_name_prefix(np, "ch-a")) node_a = of_node_get(np); else if (of_node_name_prefix(np, "ch-b")) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 3aa29d201f54..291649f02821 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -242,7 +242,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, if (mctrl & TIOCM_LOOP) port->loopback = RX_TX_CTS_RTS_SORTED; - if (!(mctrl & TIOCM_RTS)) + if (!(mctrl & TIOCM_RTS) && !uport->suspended) uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); } @@ -361,11 +361,16 @@ static int qcom_geni_serial_get_char(struct uart_port *uport) return NO_POLL_CHAR; if (word_cnt == 1 && (status & RX_LAST)) + /* + * NOTE: If RX_LAST_BYTE_VALID is 0 it needs to be + * treated as if it was BYTES_PER_FIFO_WORD. + */ private_data->poll_cached_bytes_cnt = (status & RX_LAST_BYTE_VALID_MSK) >> RX_LAST_BYTE_VALID_SHFT; - else - private_data->poll_cached_bytes_cnt = 4; + + if (private_data->poll_cached_bytes_cnt == 0) + private_data->poll_cached_bytes_cnt = BYTES_PER_FIFO_WORD; private_data->poll_cached_bytes = readl(uport->membase + SE_GENI_RX_FIFOn); @@ -995,7 +1000,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, sampling_rate = UART_OVERSAMPLING; /* Sampling rate is halved for IP versions >= 2.5 */ ver = geni_se_get_qup_hw_version(&port->se); - if (GENI_SE_VERSION_MAJOR(ver) >= 2 && GENI_SE_VERSION_MINOR(ver) >= 5) + if (ver >= QUP_SE_VERSION_2_5) sampling_rate /= 2; clk_rate = get_clk_div_rate(baud, sampling_rate, &clk_div); @@ -1098,11 +1103,11 @@ static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport) } #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE -static int __init qcom_geni_console_setup(struct console *co, char *options) +static int qcom_geni_console_setup(struct console *co, char *options) { struct uart_port *uport; struct qcom_geni_serial_port *port; - int baud = 9600; + int baud = 115200; int bits = 8; int parity = 'n'; int flow = 'n'; @@ -1433,11 +1438,9 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) return PTR_ERR(port->se.opp_table); /* OPP table is optional */ ret = dev_pm_opp_of_add_table(&pdev->dev); - if (!ret) { - port->se.has_opp_table = true; - } else if (ret != -ENODEV) { + if (ret && ret != -ENODEV) { dev_err(&pdev->dev, "invalid OPP table in device tree\n"); - return ret; + goto put_clkname; } port->private_data.drv = drv; @@ -1478,8 +1481,8 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) return 0; err: - if (port->se.has_opp_table) - dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_of_remove_table(&pdev->dev); +put_clkname: dev_pm_opp_put_clkname(port->se.opp_table); return ret; } @@ -1489,8 +1492,7 @@ static int qcom_geni_serial_remove(struct platform_device *pdev) struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); struct uart_driver *drv = port->private_data.drv; - if (port->se.has_opp_table) - dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_of_remove_table(&pdev->dev); dev_pm_opp_put_clkname(port->se.opp_table); dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c index b5ef86ae2746..85366e059258 100644 --- a/drivers/tty/serial/rda-uart.c +++ b/drivers/tty/serial/rda-uart.c @@ -259,7 +259,7 @@ static void rda_uart_set_termios(struct uart_port *port, case CS5: case CS6: dev_warn(port->dev, "bit size not supported, using 7 bits\n"); - /* Fall through */ + fallthrough; case CS7: ctrl &= ~RDA_UART_DBITS_8; break; diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index 75c2a22895f9..f5fab1dd96bc 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -879,22 +879,20 @@ static int sa1100_serial_add_one_port(struct sa1100_port *sport, struct platform static int sa1100_serial_probe(struct platform_device *dev) { - struct resource *res = dev->resource; + struct resource *res; int i; - for (i = 0; i < dev->num_resources; i++, res++) - if (res->flags & IORESOURCE_MEM) - break; - - if (i < dev->num_resources) { - for (i = 0; i < NR_PORTS; i++) { - if (sa1100_ports[i].port.mapbase != res->start) - continue; + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; - sa1100_serial_add_one_port(&sa1100_ports[i], dev); + for (i = 0; i < NR_PORTS; i++) + if (sa1100_ports[i].port.mapbase == res->start) break; - } - } + if (i == NR_PORTS) + return -ENODEV; + + sa1100_serial_add_one_port(&sa1100_ports[i], dev); return 0; } diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 8ed3482d2e1e..8ae3e03fbd8c 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -1905,9 +1905,11 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ourport->tx_irq = ret + 1; } - ret = platform_get_irq(platdev, 1); - if (ret > 0) - ourport->tx_irq = ret; + if (!s3c24xx_serial_has_interrupt_mask(port)) { + ret = platform_get_irq(platdev, 1); + if (ret > 0) + ourport->tx_irq = ret; + } /* * DMA is currently supported only on DT platforms, if DMA properties * are specified. diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index bd5e7e9938ce..22c7bc90b104 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -35,7 +35,6 @@ #include <linux/refcount.h> #include <asm/io.h> -#include <asm/war.h> #include <asm/sibyte/sb1250.h> #include <asm/sibyte/sb1250_uart.h> @@ -157,7 +156,7 @@ static unsigned char read_sbdchn(struct sbd_port *sport, int reg) unsigned char retval; retval = __read_sbdchn(sport, reg); - if (SIBYTE_1956_WAR) + if (IS_ENABLED(CONFIG_SB1_PASS_2_WORKAROUNDS)) __war_sbd1956(sport); return retval; } @@ -167,7 +166,7 @@ static unsigned char read_sbdshr(struct sbd_port *sport, int reg) unsigned char retval; retval = __read_sbdshr(sport, reg); - if (SIBYTE_1956_WAR) + if (IS_ENABLED(CONFIG_SB1_PASS_2_WORKAROUNDS)) __war_sbd1956(sport); return retval; } @@ -175,14 +174,14 @@ static unsigned char read_sbdshr(struct sbd_port *sport, int reg) static void write_sbdchn(struct sbd_port *sport, int reg, unsigned int value) { __write_sbdchn(sport, reg, value); - if (SIBYTE_1956_WAR) + if (IS_ENABLED(CONFIG_SB1_PASS_2_WORKAROUNDS)) __war_sbd1956(sport); } static void write_sbdshr(struct sbd_port *sport, int reg, unsigned int value) { __write_sbdshr(sport, reg, value); - if (SIBYTE_1956_WAR) + if (IS_ENABLED(CONFIG_SB1_PASS_2_WORKAROUNDS)) __war_sbd1956(sport); } diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 809610b37c71..f86ec2d2635b 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1271,6 +1271,7 @@ static int sc16is7xx_probe(struct device *dev, s->p[i].port.type = PORT_SC16IS7XX; s->p[i].port.fifosize = SC16IS7XX_FIFO_SIZE; s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; + s->p[i].port.iobase = i; s->p[i].port.iotype = UPIO_PORT; s->p[i].port.uartclk = freq; s->p[i].port.rs485_config = sc16is7xx_config_rs485; diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index b87914ae6da8..bd13014a1c53 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -876,7 +876,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) tegra_uart_write(tup, ier, UART_IER); break; } - /* Fall through */ + fallthrough; case 2: /* Receive */ if (!tup->use_rx_pio) { is_rx_start = tup->rx_in_progress; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 3403dd790517..f41cba10b86b 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1916,24 +1916,12 @@ static inline bool uart_console_enabled(struct uart_port *port) return uart_console(port) && (port->cons->flags & CON_ENABLED); } -static void __uart_port_spin_lock_init(struct uart_port *port) +static void uart_port_spin_lock_init(struct uart_port *port) { spin_lock_init(&port->lock); lockdep_set_class(&port->lock, &port_lock_key); } -/* - * Ensure that the serial console lock is initialised early. - * If this port is a console, then the spinlock is already initialised. - */ -static inline void uart_port_spin_lock_init(struct uart_port *port) -{ - if (uart_console(port)) - return; - - __uart_port_spin_lock_init(port); -} - #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) /** * uart_console_write - write a console message to a serial port @@ -2086,7 +2074,15 @@ uart_set_options(struct uart_port *port, struct console *co, struct ktermios termios; static struct ktermios dummy; - uart_port_spin_lock_init(port); + /* + * Ensure that the serial-console lock is initialised early. + * + * Note that the console-enabled check is needed because of kgdboc, + * which can end up calling uart_set_options() for an already enabled + * console via tty_find_polling_driver() and uart_poll_init(). + */ + if (!uart_console_enabled(port) && !port->console_reinit) + uart_port_spin_lock_init(port); memset(&termios, 0, sizeof(struct ktermios)); @@ -2101,7 +2097,7 @@ uart_set_options(struct uart_port *port, struct console *co, switch (parity) { case 'o': case 'O': termios.c_cflag |= PARODD; - /*fall through*/ + fallthrough; case 'e': case 'E': termios.c_cflag |= PARENB; break; @@ -2379,13 +2375,6 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, uart_change_pm(state, UART_PM_STATE_ON); /* - * If this driver supports console, and it hasn't been - * successfully registered yet, initialise spin lock for it. - */ - if (port->cons && !(port->cons->flags & CON_ENABLED)) - __uart_port_spin_lock_init(port); - - /* * Ensure that the modem control lines are de-activated. * keep the DTR setting that is set in uart_set_options() * We probably don't need a spinlock around this, but @@ -2637,7 +2626,7 @@ static ssize_t uartclk_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.baud_base * 16); + return sprintf(buf, "%d\n", tmp.baud_base * 16); } static ssize_t type_show(struct device *dev, @@ -2647,7 +2636,7 @@ static ssize_t type_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.type); + return sprintf(buf, "%d\n", tmp.type); } static ssize_t line_show(struct device *dev, @@ -2657,7 +2646,7 @@ static ssize_t line_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.line); + return sprintf(buf, "%d\n", tmp.line); } static ssize_t port_show(struct device *dev, @@ -2671,7 +2660,7 @@ static ssize_t port_show(struct device *dev, ioaddr = tmp.port; if (HIGH_BITS_OFFSET) ioaddr |= (unsigned long)tmp.port_high << HIGH_BITS_OFFSET; - return snprintf(buf, PAGE_SIZE, "0x%lX\n", ioaddr); + return sprintf(buf, "0x%lX\n", ioaddr); } static ssize_t irq_show(struct device *dev, @@ -2681,7 +2670,7 @@ static ssize_t irq_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.irq); + return sprintf(buf, "%d\n", tmp.irq); } static ssize_t flags_show(struct device *dev, @@ -2691,7 +2680,7 @@ static ssize_t flags_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "0x%X\n", tmp.flags); + return sprintf(buf, "0x%X\n", tmp.flags); } static ssize_t xmit_fifo_size_show(struct device *dev, @@ -2701,7 +2690,7 @@ static ssize_t xmit_fifo_size_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.xmit_fifo_size); + return sprintf(buf, "%d\n", tmp.xmit_fifo_size); } static ssize_t close_delay_show(struct device *dev, @@ -2711,7 +2700,7 @@ static ssize_t close_delay_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.close_delay); + return sprintf(buf, "%d\n", tmp.close_delay); } static ssize_t closing_wait_show(struct device *dev, @@ -2721,7 +2710,7 @@ static ssize_t closing_wait_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.closing_wait); + return sprintf(buf, "%d\n", tmp.closing_wait); } static ssize_t custom_divisor_show(struct device *dev, @@ -2731,7 +2720,7 @@ static ssize_t custom_divisor_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.custom_divisor); + return sprintf(buf, "%d\n", tmp.custom_divisor); } static ssize_t io_type_show(struct device *dev, @@ -2741,7 +2730,7 @@ static ssize_t io_type_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.io_type); + return sprintf(buf, "%d\n", tmp.io_type); } static ssize_t iomem_base_show(struct device *dev, @@ -2751,7 +2740,7 @@ static ssize_t iomem_base_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "0x%lX\n", (unsigned long)tmp.iomem_base); + return sprintf(buf, "0x%lX\n", (unsigned long)tmp.iomem_base); } static ssize_t iomem_reg_shift_show(struct device *dev, @@ -2761,7 +2750,7 @@ static ssize_t iomem_reg_shift_show(struct device *dev, struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift); + return sprintf(buf, "%d\n", tmp.iomem_reg_shift); } static ssize_t console_show(struct device *dev, @@ -2801,10 +2790,12 @@ static ssize_t console_store(struct device *dev, if (oldconsole && !newconsole) { ret = unregister_console(uport->cons); } else if (!oldconsole && newconsole) { - if (uart_console(uport)) + if (uart_console(uport)) { + uport->console_reinit = 1; register_console(uport->cons); - else + } else { ret = -ENOENT; + } } } else { ret = -ENXIO; @@ -2900,7 +2891,12 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) goto out; } - uart_port_spin_lock_init(uport); + /* + * If this port is in use as a console then the spinlock is already + * initialised. + */ + if (!uart_console_enabled(uport)) + uart_port_spin_lock_init(uport); if (uport->cons && uport->dev) of_console_check(uport->dev->of_node, uport->cons->name, uport->line); @@ -3264,9 +3260,7 @@ int uart_get_rs485_mode(struct uart_port *port) if (IS_ERR(port->rs485_term_gpio)) { ret = PTR_ERR(port->rs485_term_gpio); port->rs485_term_gpio = NULL; - if (ret != -EPROBE_DEFER) - dev_err(dev, "Cannot get rs485-term-gpios\n"); - return ret; + return dev_err_probe(dev, ret, "Cannot get rs485-term-gpios\n"); } return 0; diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index b4d89e31730e..7a07e7272de1 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -1280,6 +1280,9 @@ static int __init serial_txx9_init(void) #ifdef ENABLE_SERIAL_TXX9_PCI ret = pci_register_driver(&serial_txx9_pci_driver); + if (ret) { + platform_driver_unregister(&serial_txx9_plat_driver); + } #endif if (ret == 0) goto out; diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 143300a80090..ee6c7762d355 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -129,13 +129,9 @@ static int stm32_config_rs485(struct uart_port *port, if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { cr3 &= ~USART_CR3_DEP; rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; - mctrl_gpio_set(stm32_port->gpios, - stm32_port->port.mctrl & ~TIOCM_RTS); } else { cr3 |= USART_CR3_DEP; rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; - mctrl_gpio_set(stm32_port->gpios, - stm32_port->port.mctrl | TIOCM_RTS); } writel_relaxed(cr3, port->membase + ofs->cr3); @@ -541,17 +537,42 @@ static void stm32_disable_ms(struct uart_port *port) /* Transmit stop */ static void stm32_stop_tx(struct uart_port *port) { + struct stm32_port *stm32_port = to_stm32_port(port); + struct serial_rs485 *rs485conf = &port->rs485; + stm32_tx_interrupt_disable(port); + + if (rs485conf->flags & SER_RS485_ENABLED) { + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl & ~TIOCM_RTS); + } else { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl | TIOCM_RTS); + } + } } /* There are probably characters waiting to be transmitted. */ static void stm32_start_tx(struct uart_port *port) { + struct stm32_port *stm32_port = to_stm32_port(port); + struct serial_rs485 *rs485conf = &port->rs485; struct circ_buf *xmit = &port->state->xmit; if (uart_circ_empty(xmit)) return; + if (rs485conf->flags & SER_RS485_ENABLED) { + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl | TIOCM_RTS); + } else { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl & ~TIOCM_RTS); + } + } + stm32_transmit_chars(port); } @@ -851,13 +872,9 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { cr3 &= ~USART_CR3_DEP; rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; - mctrl_gpio_set(stm32_port->gpios, - stm32_port->port.mctrl & ~TIOCM_RTS); } else { cr3 |= USART_CR3_DEP; rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; - mctrl_gpio_set(stm32_port->gpios, - stm32_port->port.mctrl | TIOCM_RTS); } } else { @@ -970,7 +987,7 @@ static int stm32_init_port(struct stm32_port *stm32port, return ret; if (stm32port->info->cfg.has_wakeup) { - stm32port->wakeirq = platform_get_irq(pdev, 1); + stm32port->wakeirq = platform_get_irq_optional(pdev, 1); if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) return stm32port->wakeirq ? : -ENODEV; } diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 8ce9a7a256e5..319e5ceb6130 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -514,7 +514,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break) switch (ret) { case 2: sunsu_change_mouse_baud(up); - /* fallthru */ + fallthrough; case 1: break; diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 7ea06bbc6197..001e19d7c17d 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -306,7 +306,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, switch (ret) { case 2: sunzilog_change_mouse_baud(up); - /* fallthru */ + fallthrough; case 1: break; diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index 19d38b504e27..2126e6e6dfd1 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -172,9 +172,9 @@ static void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier) dev_dbg(port->dev, "%s - leaving\n", __func__); } -static void timbuart_tasklet(unsigned long arg) +static void timbuart_tasklet(struct tasklet_struct *t) { - struct timbuart_port *uart = (struct timbuart_port *)arg; + struct timbuart_port *uart = from_tasklet(uart, t, tasklet); u32 isr, ier = 0; spin_lock(&uart->port.lock); @@ -451,7 +451,7 @@ static int timbuart_probe(struct platform_device *dev) } uart->port.irq = irq; - tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart); + tasklet_setup(&uart->tasklet, timbuart_tasklet); err = uart_register_driver(&timbuart_driver); if (err) diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 3c8c662c69e2..d6a8604157ab 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -283,7 +283,7 @@ static unsigned int qe_uart_tx_empty(struct uart_port *port) * don't need that support. This function must exist, however, otherwise * the kernel will panic. */ -void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +static void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { } diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 2833f1418d6d..a9b1ee27183a 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -544,7 +544,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, cdns_uart->baud = cdns_uart_set_baud_rate(cdns_uart->port, cdns_uart->baud); - /* fall through */ + fallthrough; case ABORT_RATE_CHANGE: if (!locked) spin_lock_irqsave(&cdns_uart->port->lock, flags); diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 0dba40eace46..c8324d58ef56 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -942,7 +942,7 @@ static inline int mgsl_paranoia_check(struct mgsl_struct *info, return 0; } -/** +/* * line discipline callback wrappers * * The wrappers maintain line discipline references @@ -7419,14 +7419,14 @@ static int usc_loopmode_active( struct mgsl_struct * info) #if SYNCLINK_GENERIC_HDLC /** - * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) - * set encoding and frame check sequence (FCS) options + * hdlcdev_attach - called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) + * @dev: pointer to network device structure + * @encoding: serial encoding setting + * @parity: FCS setting * - * dev pointer to network device structure - * encoding serial encoding setting - * parity FCS setting + * Set encoding and frame check sequence (FCS) options. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) @@ -7468,10 +7468,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, } /** - * called by generic HDLC layer to send frame - * - * skb socket buffer containing HDLC frame - * dev pointer to network device structure + * hdlcdev_xmit - called by generic HDLC layer to send a frame + * @skb: socket buffer containing HDLC frame + * @dev: pointer to network device structure */ static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) @@ -7509,12 +7508,12 @@ static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, } /** - * called by network layer when interface enabled - * claim resources and initialize hardware + * hdlcdev_open - called by network layer when interface enabled + * @dev: pointer to network device structure * - * dev pointer to network device structure + * Claim resources and initialize hardware. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_open(struct net_device *dev) { @@ -7568,12 +7567,12 @@ static int hdlcdev_open(struct net_device *dev) } /** - * called by network layer when interface is disabled - * shutdown hardware and release resources + * hdlcdev_close - called by network layer when interface is disabled + * @dev: pointer to network device structure * - * dev pointer to network device structure + * Shutdown hardware and release resources. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_close(struct net_device *dev) { @@ -7598,13 +7597,12 @@ static int hdlcdev_close(struct net_device *dev) } /** - * called by network layer to process IOCTL call to network device - * - * dev pointer to network device structure - * ifr pointer to network interface request structure - * cmd IOCTL command code + * hdlcdev_ioctl - called by network layer to process IOCTL call to network device + * @dev: pointer to network device structure + * @ifr: pointer to network interface request structure + * @cmd: IOCTL command code * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { @@ -7702,9 +7700,9 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } /** - * called by network layer when transmit timeout is detected + * hdlcdev_tx_timeout - called by network layer when transmit timeout is detected * - * dev pointer to network device structure + * @dev: pointer to network device structure */ static void hdlcdev_tx_timeout(struct net_device *dev, unsigned int txqueue) { @@ -7725,10 +7723,10 @@ static void hdlcdev_tx_timeout(struct net_device *dev, unsigned int txqueue) } /** - * called by device driver when transmit completes - * reenable network layer transmit if stopped + * hdlcdev_tx_done - called by device driver when transmit completes + * @info: pointer to device instance information * - * info pointer to device instance information + * Reenable network layer transmit if stopped. */ static void hdlcdev_tx_done(struct mgsl_struct *info) { @@ -7737,12 +7735,12 @@ static void hdlcdev_tx_done(struct mgsl_struct *info) } /** - * called by device driver when frame received - * pass frame to network layer + * hdlcdev_rx - called by device driver when frame received + * @info: pointer to device instance information + * @buf: pointer to buffer contianing frame data + * @size: count of data bytes in buf * - * info pointer to device instance information - * buf pointer to buffer contianing frame data - * size count of data bytes in buf + * Pass frame to network layer. */ static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size) { @@ -7778,12 +7776,12 @@ static const struct net_device_ops hdlcdev_ops = { }; /** - * called by device driver when adding device instance - * do generic HDLC initialization + * hdlcdev_init - called by device driver when adding device instance + * @info: pointer to device instance information * - * info pointer to device instance information + * Do generic HDLC initialization. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_init(struct mgsl_struct *info) { @@ -7827,10 +7825,10 @@ static int hdlcdev_init(struct mgsl_struct *info) } /** - * called by device driver when removing device instance - * do generic HDLC cleanup + * hdlcdev_exit - called by device driver when removing device instance + * @info: pointer to device instance information * - * info pointer to device instance information + * Do generic HDLC cleanup. */ static void hdlcdev_exit(struct mgsl_struct *info) { diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index b794177ccfb9..afa4cc52e48d 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -1395,14 +1395,14 @@ static int set_break(struct tty_struct *tty, int break_state) #if SYNCLINK_GENERIC_HDLC /** - * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) - * set encoding and frame check sequence (FCS) options + * hdlcdev_attach - called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) + * @dev: pointer to network device structure + * @encoding: serial encoding setting + * @parity: FCS setting * - * dev pointer to network device structure - * encoding serial encoding setting - * parity FCS setting + * Set encoding and frame check sequence (FCS) options. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) @@ -1446,10 +1446,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, } /** - * called by generic HDLC layer to send frame - * - * skb socket buffer containing HDLC frame - * dev pointer to network device structure + * hdlcdev_xmit - called by generic HDLC layer to send a frame + * @skb: socket buffer containing HDLC frame + * @dev: pointer to network device structure */ static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) @@ -1483,12 +1482,12 @@ static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, } /** - * called by network layer when interface enabled - * claim resources and initialize hardware + * hdlcdev_open - called by network layer when interface enabled + * @dev: pointer to network device structure * - * dev pointer to network device structure + * Claim resources and initialize hardware. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_open(struct net_device *dev) { @@ -1544,12 +1543,12 @@ static int hdlcdev_open(struct net_device *dev) } /** - * called by network layer when interface is disabled - * shutdown hardware and release resources + * hdlcdev_close - called by network layer when interface is disabled + * @dev: pointer to network device structure * - * dev pointer to network device structure + * Shutdown hardware and release resources. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_close(struct net_device *dev) { @@ -1574,13 +1573,12 @@ static int hdlcdev_close(struct net_device *dev) } /** - * called by network layer to process IOCTL call to network device - * - * dev pointer to network device structure - * ifr pointer to network interface request structure - * cmd IOCTL command code + * hdlcdev_ioctl - called by network layer to process IOCTL call to network device + * @dev: pointer to network device structure + * @ifr: pointer to network interface request structure + * @cmd: IOCTL command code * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { @@ -1678,9 +1676,8 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } /** - * called by network layer when transmit timeout is detected - * - * dev pointer to network device structure + * hdlcdev_tx_timeout - called by network layer when transmit timeout is detected + * @dev: pointer to network device structure */ static void hdlcdev_tx_timeout(struct net_device *dev, unsigned int txqueue) { @@ -1700,10 +1697,10 @@ static void hdlcdev_tx_timeout(struct net_device *dev, unsigned int txqueue) } /** - * called by device driver when transmit completes - * reenable network layer transmit if stopped + * hdlcdev_tx_done - called by device driver when transmit completes + * @info: pointer to device instance information * - * info pointer to device instance information + * Reenable network layer transmit if stopped. */ static void hdlcdev_tx_done(struct slgt_info *info) { @@ -1712,12 +1709,12 @@ static void hdlcdev_tx_done(struct slgt_info *info) } /** - * called by device driver when frame received - * pass frame to network layer + * hdlcdev_rx - called by device driver when frame received + * @info: pointer to device instance information + * @buf: pointer to buffer contianing frame data + * @size: count of data bytes in buf * - * info pointer to device instance information - * buf pointer to buffer contianing frame data - * size count of data bytes in buf + * Pass frame to network layer. */ static void hdlcdev_rx(struct slgt_info *info, char *buf, int size) { @@ -1751,12 +1748,12 @@ static const struct net_device_ops hdlcdev_ops = { }; /** - * called by device driver when adding device instance - * do generic HDLC initialization + * hdlcdev_init - called by device driver when adding device instance + * @info: pointer to device instance information * - * info pointer to device instance information + * Do generic HDLC initialization. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_init(struct slgt_info *info) { @@ -1800,10 +1797,10 @@ static int hdlcdev_init(struct slgt_info *info) } /** - * called by device driver when removing device instance - * do generic HDLC cleanup + * hdlcdev_exit - called by device driver when removing device instance + * @info: pointer to device instance information * - * info pointer to device instance information + * Do generic HDLC cleanup. */ static void hdlcdev_exit(struct slgt_info *info) { @@ -3341,8 +3338,8 @@ static int alloc_desc(struct slgt_info *info) unsigned int pbufs; /* allocate memory to hold descriptor lists */ - info->bufs = pci_zalloc_consistent(info->pdev, DESC_LIST_SIZE, - &info->bufs_dma_addr); + info->bufs = dma_alloc_coherent(&info->pdev->dev, DESC_LIST_SIZE, + &info->bufs_dma_addr, GFP_KERNEL); if (info->bufs == NULL) return -ENOMEM; @@ -3384,7 +3381,8 @@ static int alloc_desc(struct slgt_info *info) static void free_desc(struct slgt_info *info) { if (info->bufs != NULL) { - pci_free_consistent(info->pdev, DESC_LIST_SIZE, info->bufs, info->bufs_dma_addr); + dma_free_coherent(&info->pdev->dev, DESC_LIST_SIZE, + info->bufs, info->bufs_dma_addr); info->bufs = NULL; info->rbufs = NULL; info->tbufs = NULL; @@ -3395,7 +3393,9 @@ static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count) { int i; for (i=0; i < count; i++) { - if ((bufs[i].buf = pci_alloc_consistent(info->pdev, DMABUFSIZE, &bufs[i].buf_dma_addr)) == NULL) + bufs[i].buf = dma_alloc_coherent(&info->pdev->dev, DMABUFSIZE, + &bufs[i].buf_dma_addr, GFP_KERNEL); + if (!bufs[i].buf) return -ENOMEM; bufs[i].pbuf = cpu_to_le32((unsigned int)bufs[i].buf_dma_addr); } @@ -3408,7 +3408,8 @@ static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count) for (i=0; i < count; i++) { if (bufs[i].buf == NULL) continue; - pci_free_consistent(info->pdev, DMABUFSIZE, bufs[i].buf, bufs[i].buf_dma_addr); + dma_free_coherent(&info->pdev->dev, DMABUFSIZE, bufs[i].buf, + bufs[i].buf_dma_addr); bufs[i].buf = NULL; } } diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 33ff2dbb6650..ce08c5ec331c 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -685,7 +685,7 @@ static inline int sanity_check(SLMP_INFO *info, return 0; } -/** +/* * line discipline callback wrappers * * The wrappers maintain line discipline references @@ -1520,14 +1520,14 @@ static int set_break(struct tty_struct *tty, int break_state) #if SYNCLINK_GENERIC_HDLC /** - * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) - * set encoding and frame check sequence (FCS) options + * hdlcdev_attach - called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) + * @dev: pointer to network device structure + * @encoding: serial encoding setting + * @parity: FCS setting * - * dev pointer to network device structure - * encoding serial encoding setting - * parity FCS setting + * Set encoding and frame check sequence (FCS) options. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) @@ -1569,10 +1569,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, } /** - * called by generic HDLC layer to send frame - * - * skb socket buffer containing HDLC frame - * dev pointer to network device structure + * hdlcdev_xmit - called by generic HDLC layer to send frame + * @skb: socket buffer containing HDLC frame + * @dev: pointer to network device structure */ static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) @@ -1610,12 +1609,12 @@ static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, } /** - * called by network layer when interface enabled - * claim resources and initialize hardware + * hdlcdev_open - called by network layer when interface enabled + * @dev: pointer to network device structure * - * dev pointer to network device structure + * Claim resources and initialize hardware. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_open(struct net_device *dev) { @@ -1669,12 +1668,12 @@ static int hdlcdev_open(struct net_device *dev) } /** - * called by network layer when interface is disabled - * shutdown hardware and release resources + * hdlcdev_close - called by network layer when interface is disabled + * @dev: pointer to network device structure * - * dev pointer to network device structure + * Shutdown hardware and release resources. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_close(struct net_device *dev) { @@ -1699,13 +1698,12 @@ static int hdlcdev_close(struct net_device *dev) } /** - * called by network layer to process IOCTL call to network device + * hdlcdev_ioctl - called by network layer to process IOCTL call to network device + * @dev: pointer to network device structure + * @ifr: pointer to network interface request structure + * @cmd: IOCTL command code * - * dev pointer to network device structure - * ifr pointer to network interface request structure - * cmd IOCTL command code - * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { @@ -1803,9 +1801,8 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } /** - * called by network layer when transmit timeout is detected - * - * dev pointer to network device structure + * hdlcdev_tx_timeout - called by network layer when transmit timeout is detected + * @dev: pointer to network device structure */ static void hdlcdev_tx_timeout(struct net_device *dev, unsigned int txqueue) { @@ -1826,10 +1823,10 @@ static void hdlcdev_tx_timeout(struct net_device *dev, unsigned int txqueue) } /** - * called by device driver when transmit completes - * reenable network layer transmit if stopped + * hdlcdev_tx_done - called by device driver when transmit completes + * @info: pointer to device instance information * - * info pointer to device instance information + * Reenable network layer transmit if stopped. */ static void hdlcdev_tx_done(SLMP_INFO *info) { @@ -1838,12 +1835,12 @@ static void hdlcdev_tx_done(SLMP_INFO *info) } /** - * called by device driver when frame received - * pass frame to network layer + * hdlcdev_rx - called by device driver when frame received + * @info: pointer to device instance information + * @buf: pointer to buffer contianing frame data + * @size: count of data bytes in buf * - * info pointer to device instance information - * buf pointer to buffer contianing frame data - * size count of data bytes in buf + * Pass frame to network layer. */ static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size) { @@ -1879,12 +1876,12 @@ static const struct net_device_ops hdlcdev_ops = { }; /** - * called by device driver when adding device instance - * do generic HDLC initialization + * hdlcdev_init - called by device driver when adding device instance + * @info: pointer to device instance information * - * info pointer to device instance information + * Do generic HDLC initialization. * - * returns 0 if success, otherwise error code + * Return: 0 if success, otherwise error code */ static int hdlcdev_init(SLMP_INFO *info) { @@ -1928,10 +1925,10 @@ static int hdlcdev_init(SLMP_INFO *info) } /** - * called by device driver when removing device instance - * do generic HDLC cleanup + * hdlcdev_exit - called by device driver when removing device instance + * @info: pointer to device instance information * - * info pointer to device instance information + * Do generic HDLC cleanup. */ static void hdlcdev_exit(SLMP_INFO *info) { diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index a8e39b2cdd55..959f9e121cc6 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -19,6 +19,7 @@ #include <linux/sched/rt.h> #include <linux/sched/debug.h> #include <linux/sched/task.h> +#include <linux/ctype.h> #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/fs.h> @@ -440,7 +441,7 @@ static const struct sysrq_key_op sysrq_unrt_op = { /* Key Operations table and lock */ static DEFINE_SPINLOCK(sysrq_key_table_lock); -static const struct sysrq_key_op *sysrq_key_table[36] = { +static const struct sysrq_key_op *sysrq_key_table[62] = { &sysrq_loglevel_op, /* 0 */ &sysrq_loglevel_op, /* 1 */ &sysrq_loglevel_op, /* 2 */ @@ -497,6 +498,32 @@ static const struct sysrq_key_op *sysrq_key_table[36] = { /* y: May be registered on sparc64 for global register dump */ NULL, /* y */ &sysrq_ftrace_dump_op, /* z */ + NULL, /* A */ + NULL, /* B */ + NULL, /* C */ + NULL, /* D */ + NULL, /* E */ + NULL, /* F */ + NULL, /* G */ + NULL, /* H */ + NULL, /* I */ + NULL, /* J */ + NULL, /* K */ + NULL, /* L */ + NULL, /* M */ + NULL, /* N */ + NULL, /* O */ + NULL, /* P */ + NULL, /* Q */ + NULL, /* R */ + NULL, /* S */ + NULL, /* T */ + NULL, /* U */ + NULL, /* V */ + NULL, /* W */ + NULL, /* X */ + NULL, /* Y */ + NULL, /* Z */ }; /* key2index calculation, -1 on invalid index */ @@ -508,6 +535,8 @@ static int sysrq_key_table_key2index(int key) retval = key - '0'; else if ((key >= 'a') && (key <= 'z')) retval = key + 10 - 'a'; + else if ((key >= 'A') && (key <= 'Z')) + retval = key + 36 - 'A'; else retval = -1; return retval; @@ -621,6 +650,8 @@ struct sysrq_state { unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; unsigned int alt; unsigned int alt_use; + unsigned int shift; + unsigned int shift_use; bool active; bool need_reinject; bool reinjecting; @@ -805,10 +836,20 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq, } break; + case KEY_LEFTSHIFT: + case KEY_RIGHTSHIFT: + if (!value) + sysrq->shift = KEY_RESERVED; + else if (value != 2) + sysrq->shift = code; + break; + case KEY_SYSRQ: if (value == 1 && sysrq->alt != KEY_RESERVED) { sysrq->active = true; sysrq->alt_use = sysrq->alt; + /* either RESERVED (for released) or actual code */ + sysrq->shift_use = sysrq->shift; /* * If nothing else will be pressed we'll need * to re-inject Alt-SysRq keysroke. @@ -831,8 +872,12 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq, default: if (sysrq->active && value && value != 2) { + unsigned char c = sysrq_xlate[code]; + sysrq->need_reinject = false; - __handle_sysrq(sysrq_xlate[code], true); + if (sysrq->shift_use != KEY_RESERVED) + c = toupper(c); + __handle_sysrq(c, true); } break; } diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c index 40207cab3b2a..84fec3c62d6a 100644 --- a/drivers/tty/tty_baudrate.c +++ b/drivers/tty/tty_baudrate.c @@ -119,8 +119,8 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate); /** * tty_termios_encode_baud_rate * @termios: ktermios structure holding user requested state - * @ispeed: input speed - * @ospeed: output speed + * @ibaud: input speed + * @obaud: output speed * * Encode the speeds set into the passed termios structure. This is * used as a library helper for drivers so that they can report back @@ -223,7 +223,7 @@ EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); /** * tty_encode_baud_rate - set baud rate of the tty * @ibaud: input baud rate - * @obad: output baud rate + * @obaud: output baud rate * * Update the current termios data for the tty with the new speed * settings. The caller must hold the termios_rwsem for the tty in diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index ec145a59f199..bd2d91546e32 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -42,7 +42,7 @@ * tty_buffer_lock_exclusive - gain exclusive access to buffer * tty_buffer_unlock_exclusive - release exclusive access * - * @port - tty_port owning the flip buffer + * @port: tty port owning the flip buffer * * Guarantees safe use of the line discipline's receive_buf() method by * excluding the buffer work and any pending flush from using the flip @@ -78,7 +78,7 @@ EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive); /** * tty_buffer_space_avail - return unused buffer space - * @port - tty_port owning the flip buffer + * @port: tty port owning the flip buffer * * Returns the # of bytes which can be written by the driver without * reaching the buffer limit. @@ -107,7 +107,7 @@ static void tty_buffer_reset(struct tty_buffer *p, size_t size) /** * tty_buffer_free_all - free buffers used by a tty - * @tty: tty to free from + * @port: tty port to free from * * Remove all the buffers pending on a tty whether queued with data * or in the free ring. Must be called when the tty is no longer in use @@ -142,7 +142,7 @@ void tty_buffer_free_all(struct tty_port *port) /** * tty_buffer_alloc - allocate a tty buffer - * @tty: tty device + * @port: tty port * @size: desired size (characters) * * Allocate a new tty buffer to hold the desired number of characters. @@ -184,7 +184,7 @@ found: /** * tty_buffer_free - free a tty buffer - * @tty: tty owning the buffer + * @port: tty port owning the buffer * @b: the buffer to free * * Free a tty buffer, or add it to the free list according to our @@ -243,7 +243,7 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) /** * tty_buffer_request_room - grow tty buffer if needed - * @tty: tty structure + * @port: tty port * @size: size desired * @flags: buffer flags if new buffer allocated (default = 0) * @@ -559,7 +559,7 @@ EXPORT_SYMBOL(tty_flip_buffer_push); /** * tty_buffer_init - prepare a tty buffer structure - * @tty: tty to initialise + * @port: tty port to initialise * * Set up the initial state of the buffer management for a tty device. * Must be called before the other tty buffer functions are used. diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index ceed72c9a88f..9f8b9a567b35 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -307,7 +307,7 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) /** * get_tty_driver - find device of a tty - * @dev_t: device identifier + * @device: device identifier * @index: returns the index of the tty * * This routine returns a tty driver structure, given a device number @@ -544,7 +544,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup); /** * __tty_hangup - actual handler for hangup events - * @work: tty device + * @tty: tty device * * This can be called by a "kworker" kernel thread. That is process * synchronous but doesn't hold any locks, so we need to make sure we @@ -1232,7 +1232,7 @@ static int tty_driver_install_tty(struct tty_driver *driver, /** * tty_driver_remove_tty() - remove a tty from the driver tables * @driver: the driver for the tty - * @idx: the minor number + * @tty: tty to remove * * Remvoe a tty object from the driver tables. The tty->index field * will be set by the time this is called. @@ -1247,9 +1247,9 @@ static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct * driver->ttys[tty->index] = NULL; } -/* - * tty_reopen() - fast re-open of an open tty - * @tty - the tty to open +/** + * tty_reopen() - fast re-open of an open tty + * @tty: the tty to open * * Return 0 on success, -errno on error. * Re-opens on master ptys are not allowed and return -EIO. @@ -1295,7 +1295,6 @@ static int tty_reopen(struct tty_struct *tty) * tty_init_dev - initialise a tty device * @driver: tty driver we are opening a device on * @idx: device index - * @ret_tty: returned tty structure * * Prepare a tty device. This may not be a "new" clean device but * could also be an active device. The pty drivers require special @@ -1313,6 +1312,8 @@ static int tty_reopen(struct tty_struct *tty) * failed open. The new code protects the open with a mutex, so it's * really quite straightforward. The mutex locking can probably be * relaxed for the (most common) case of reopening a tty. + * + * Return: returned tty structure */ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) @@ -1432,7 +1433,7 @@ static void tty_flush_works(struct tty_struct *tty) /** * release_one_tty - release tty structure memory - * @kref: kref of tty we are obliterating + * @work: work of tty we are obliterating * * Releases memory associated with a tty structure, and clears out the * driver table slots. This function is called when a device is no longer @@ -1514,10 +1515,12 @@ static void release_tty(struct tty_struct *tty, int idx) tty->ops->shutdown(tty); tty_save_termios(tty); tty_driver_remove_tty(tty->driver, tty); - tty->port->itty = NULL; + if (tty->port) + tty->port->itty = NULL; if (tty->link) tty->link->port->itty = NULL; - tty_buffer_cancel_work(tty->port); + if (tty->port) + tty_buffer_cancel_work(tty->port); if (tty->link) tty_buffer_cancel_work(tty->link->port); @@ -1528,7 +1531,6 @@ static void release_tty(struct tty_struct *tty, int idx) /** * tty_release_checks - check a tty before real release * @tty: tty to check - * @o_tty: link of @tty (if any) * @idx: index of the tty * * Performs some paranoid checking before true release of the @tty. @@ -2200,7 +2202,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p) /** * tiocgwinsz - implement window query ioctl - * @tty; tty + * @tty: tty * @arg: user buffer for result * * Copies the kernel idea of the window size into the user buffer. @@ -2223,8 +2225,7 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) /** * tty_do_resize - resize event * @tty: tty being resized - * @rows: rows (character) - * @cols: cols (character) + * @ws: new dimensions * * Update the termios variables and send the necessary signals to * peform a terminal resize correctly @@ -2254,7 +2255,7 @@ EXPORT_SYMBOL(tty_do_resize); /** * tiocswinsz - implement window size set ioctl - * @tty; tty side of tty + * @tty: tty side of tty * @arg: user buffer for result * * Copies the user idea of the window size to the kernel. Traditionally @@ -2402,7 +2403,6 @@ out: /** * tty_tiocmget - get modem status * @tty: tty device - * @file: user file pointer * @p: pointer to result * * Obtain the modem status bits from the tty driver if the feature diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 9245fffdbceb..e18f318586ab 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -866,7 +866,7 @@ static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg) ld->ops->flush_buffer(tty); tty_unthrottle(tty); } - /* fall through */ + fallthrough; case TCOFLUSH: tty_driver_flush_buffer(tty); break; diff --git a/drivers/tty/tty_jobctrl.c b/drivers/tty/tty_jobctrl.c index f8ed50a16848..28a23a0fef21 100644 --- a/drivers/tty/tty_jobctrl.c +++ b/drivers/tty/tty_jobctrl.c @@ -178,8 +178,8 @@ void session_clear_tty(struct pid *session) /** * tty_signal_session_leader - sends SIGHUP to session leader - * @tty controlling tty - * @exit_session if non-zero, signal all foreground group processes + * @tty: controlling tty + * @exit_session: if non-zero, signal all foreground group processes * * Send SIGHUP and SIGCONT to the session leader and its process group. * Optionally, signal all processes in the foreground process group. diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index ec1f6a48121e..fe37ec331289 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -79,7 +79,6 @@ EXPORT_SYMBOL(tty_register_ldisc); /** * tty_unregister_ldisc - unload a line discipline * @disc: ldisc number - * @new_ldisc: pointer to the ldisc object * * Remove a line discipline from the kernel providing it is not * currently in use. @@ -542,7 +541,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) /** * tty_set_ldisc - set line discipline * @tty: the terminal to set - * @ldisc: the line discipline + * @disc: the line discipline number * * Set the discipline of a tty line. Must be called from a process * context. The ldisc change logic has to protect itself against any diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 5947b54d92be..5d778c0aa009 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -268,7 +268,7 @@ unsigned short *set_translate(int m, struct vc_data *vc) * was active. * Still, it is now possible to a certain extent to cut and paste non-ASCII. */ -u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode) +u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode) { struct uni_pagedir *p; int m; @@ -708,7 +708,7 @@ EXPORT_SYMBOL(con_set_default_unimap); /** * con_copy_unimap - copy unimap between two vts * @dst_vc: target - * @src_vt: source + * @src_vc: source * * The caller must hold the console lock when invoking this method */ diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 0db53b5b3acf..78acc270e39a 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -743,8 +743,13 @@ static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) return; if ((unsigned)value < ARRAY_SIZE(func_table)) { + unsigned long flags; + + spin_lock_irqsave(&func_buf_lock, flags); if (func_table[value]) puts_queue(vc, func_table[value]); + spin_unlock_irqrestore(&func_buf_lock, flags); + } else pr_err("k_fn called with value=%d\n", value); } @@ -1991,13 +1996,11 @@ out: #undef s #undef v -/* FIXME: This one needs untangling and locking */ +/* FIXME: This one needs untangling */ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) { struct kbsentry *kbs; - char *p; u_char *q; - u_char __user *up; int sz, fnw_sz; int delta; char *first_free, *fj, *fnw; @@ -2023,23 +2026,19 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) i = array_index_nospec(kbs->kb_func, MAX_NR_FUNC); switch (cmd) { - case KDGKBSENT: - sz = sizeof(kbs->kb_string) - 1; /* sz should have been - a struct member */ - up = user_kdgkb->kb_string; - p = func_table[i]; - if(p) - for ( ; *p && sz; p++, sz--) - if (put_user(*p, up++)) { - ret = -EFAULT; - goto reterr; - } - if (put_user('\0', up)) { - ret = -EFAULT; - goto reterr; - } - kfree(kbs); - return ((p && *p) ? -EOVERFLOW : 0); + case KDGKBSENT: { + /* size should have been a struct member */ + ssize_t len = sizeof(user_kdgkb->kb_string); + + spin_lock_irqsave(&func_buf_lock, flags); + len = strlcpy(kbs->kb_string, func_table[i] ? : "", len); + spin_unlock_irqrestore(&func_buf_lock, flags); + + ret = copy_to_user(user_kdgkb->kb_string, kbs->kb_string, + len + 1) ? -EFAULT : 0; + + goto reterr; + } case KDSKBSENT: if (!perm) { ret = -EPERM; diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 8e74654c1b27..f245a5acf7e9 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -54,7 +54,7 @@ static struct vc_selection { /* set reverse video on characters s-e of console with selection. */ static inline void highlight(const int s, const int e) { - invert_screen(vc_sel.cons, s, e-s+2, 1); + invert_screen(vc_sel.cons, s, e-s+2, true); } /* use complementary color to show the pointer */ diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 778f83ea2249..1850bacdb5b0 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -50,11 +50,7 @@ #include <asm/byteorder.h> #include <asm/unaligned.h> -#undef attr -#undef org -#undef addr -#define HEADER_SIZE 4 - +#define HEADER_SIZE 4u #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE) /* @@ -177,12 +173,14 @@ vcs_poll_data_get(struct file *file) return poll; } -/* - * Returns VC for inode. +/** + * vcs_vc -- return VC for @inode + * @inode: inode for which to return a VC + * @viewed: returns whether this console is currently foreground (viewed) + * * Must be called with console_lock. */ -static struct vc_data* -vcs_vc(struct inode *inode, int *viewed) +static struct vc_data *vcs_vc(struct inode *inode, bool *viewed) { unsigned int currcons = console(inode); @@ -191,54 +189,177 @@ vcs_vc(struct inode *inode, int *viewed) if (currcons == 0) { currcons = fg_console; if (viewed) - *viewed = 1; + *viewed = true; } else { currcons--; if (viewed) - *viewed = 0; + *viewed = false; } return vc_cons[currcons].d; } -/* - * Returns size for VC carried by inode. +/** + * vcs_size -- return size for a VC in @vc + * @vc: which VC + * @attr: does it use attributes? + * @unicode: is it unicode? + * * Must be called with console_lock. */ -static int -vcs_size(struct inode *inode) +static int vcs_size(const struct vc_data *vc, bool attr, bool unicode) { int size; - struct vc_data *vc; WARN_CONSOLE_UNLOCKED(); - vc = vcs_vc(inode, NULL); - if (!vc) - return -ENXIO; - size = vc->vc_rows * vc->vc_cols; - if (use_attributes(inode)) { - if (use_unicode(inode)) + if (attr) { + if (unicode) return -EOPNOTSUPP; - size = 2*size + HEADER_SIZE; - } else if (use_unicode(inode)) + + size = 2 * size + HEADER_SIZE; + } else if (unicode) size *= 4; + return size; } static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) { + struct inode *inode = file_inode(file); + struct vc_data *vc; int size; console_lock(); - size = vcs_size(file_inode(file)); + vc = vcs_vc(inode, NULL); + if (!vc) { + console_unlock(); + return -ENXIO; + } + + size = vcs_size(vc, use_attributes(inode), use_unicode(inode)); console_unlock(); if (size < 0) return size; return fixed_size_llseek(file, offset, orig, size); } +static int vcs_read_buf_uni(struct vc_data *vc, char *con_buf, + unsigned int pos, unsigned int count, bool viewed) +{ + unsigned int nr, row, col, maxcol = vc->vc_cols; + int ret; + + ret = vc_uniscr_check(vc); + if (ret) + return ret; + + pos /= 4; + row = pos / maxcol; + col = pos % maxcol; + nr = maxcol - col; + do { + if (nr > count / 4) + nr = count / 4; + vc_uniscr_copy_line(vc, con_buf, viewed, row, col, nr); + con_buf += nr * 4; + count -= nr * 4; + row++; + col = 0; + nr = maxcol; + } while (count); + + return 0; +} + +static void vcs_read_buf_noattr(const struct vc_data *vc, char *con_buf, + unsigned int pos, unsigned int count, bool viewed) +{ + u16 *org; + unsigned int col, maxcol = vc->vc_cols; + + org = screen_pos(vc, pos, viewed); + col = pos % maxcol; + pos += maxcol - col; + + while (count-- > 0) { + *con_buf++ = (vcs_scr_readw(vc, org++) & 0xff); + if (++col == maxcol) { + org = screen_pos(vc, pos, viewed); + col = 0; + pos += maxcol; + } + } +} + +static unsigned int vcs_read_buf(const struct vc_data *vc, char *con_buf, + unsigned int pos, unsigned int count, bool viewed, + unsigned int *skip) +{ + u16 *org, *con_buf16; + unsigned int col, maxcol = vc->vc_cols; + unsigned int filled = count; + + if (pos < HEADER_SIZE) { + /* clamp header values if they don't fit */ + con_buf[0] = min(vc->vc_rows, 0xFFu); + con_buf[1] = min(vc->vc_cols, 0xFFu); + getconsxy(vc, con_buf + 2); + + *skip += pos; + count += pos; + if (count > CON_BUF_SIZE) { + count = CON_BUF_SIZE; + filled = count - pos; + } + + /* Advance state pointers and move on. */ + count -= min(HEADER_SIZE, count); + pos = HEADER_SIZE; + con_buf += HEADER_SIZE; + /* If count >= 0, then pos is even... */ + } else if (pos & 1) { + /* + * Skip first byte for output if start address is odd. Update + * region sizes up/down depending on free space in buffer. + */ + (*skip)++; + if (count < CON_BUF_SIZE) + count++; + else + filled--; + } + + if (!count) + return filled; + + pos -= HEADER_SIZE; + pos /= 2; + col = pos % maxcol; + + org = screen_pos(vc, pos, viewed); + pos += maxcol - col; + + /* + * Buffer has even length, so we can always copy character + attribute. + * We do not copy last byte to userspace if count is odd. + */ + count = (count + 1) / 2; + con_buf16 = (u16 *)con_buf; + + while (count) { + *con_buf16++ = vcs_scr_readw(vc, org++); + count--; + if (++col == maxcol) { + org = screen_pos(vc, pos, viewed); + col = 0; + pos += maxcol; + } + } + + return filled; +} static ssize_t vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -246,11 +367,11 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct inode *inode = file_inode(file); struct vc_data *vc; struct vcs_poll_data *poll; - long pos, read; - int attr, uni_mode, row, col, maxcol, viewed; - unsigned short *org = NULL; + 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); if (!con_buf) @@ -283,16 +404,14 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) read = 0; ret = 0; while (count) { - char *con_buf0, *con_buf_start; - long this_round, size; - ssize_t orig_count; - long p = pos; + unsigned int this_round, skip = 0; + int size; /* Check whether we are above size each round, * as copy_to_user at the end of this loop * could sleep. */ - size = vcs_size(inode); + size = vcs_size(vc, attr, uni_mode); if (size < 0) { if (read) break; @@ -313,104 +432,17 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) * attempt to move it to userspace. */ - con_buf_start = con_buf0 = con_buf; - orig_count = this_round; - maxcol = vc->vc_cols; if (uni_mode) { - unsigned int nr; - - ret = vc_uniscr_check(vc); + ret = vcs_read_buf_uni(vc, con_buf, pos, this_round, + viewed); if (ret) break; - p /= 4; - row = p / vc->vc_cols; - col = p % maxcol; - nr = maxcol - col; - do { - if (nr > this_round/4) - nr = this_round/4; - vc_uniscr_copy_line(vc, con_buf0, viewed, - row, col, nr); - con_buf0 += nr * 4; - this_round -= nr * 4; - row++; - col = 0; - nr = maxcol; - } while (this_round); } else if (!attr) { - org = screen_pos(vc, p, viewed); - col = p % maxcol; - p += maxcol - col; - while (this_round-- > 0) { - *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff); - if (++col == maxcol) { - org = screen_pos(vc, p, viewed); - col = 0; - p += maxcol; - } - } + vcs_read_buf_noattr(vc, con_buf, pos, this_round, + viewed); } else { - if (p < HEADER_SIZE) { - size_t tmp_count; - - /* clamp header values if they don't fit */ - con_buf0[0] = min(vc->vc_rows, 0xFFu); - con_buf0[1] = min(vc->vc_cols, 0xFFu); - getconsxy(vc, con_buf0 + 2); - - con_buf_start += p; - this_round += p; - if (this_round > CON_BUF_SIZE) { - this_round = CON_BUF_SIZE; - orig_count = this_round - p; - } - - tmp_count = HEADER_SIZE; - if (tmp_count > this_round) - tmp_count = this_round; - - /* Advance state pointers and move on. */ - this_round -= tmp_count; - p = HEADER_SIZE; - con_buf0 = con_buf + HEADER_SIZE; - /* If this_round >= 0, then p is even... */ - } else if (p & 1) { - /* Skip first byte for output if start address is odd - * Update region sizes up/down depending on free - * space in buffer. - */ - con_buf_start++; - if (this_round < CON_BUF_SIZE) - this_round++; - else - orig_count--; - } - if (this_round > 0) { - unsigned short *tmp_buf = (unsigned short *)con_buf0; - - p -= HEADER_SIZE; - p /= 2; - col = p % maxcol; - - org = screen_pos(vc, p, viewed); - p += maxcol - col; - - /* Buffer has even length, so we can always copy - * character + attribute. We do not copy last byte - * to userspace if this_round is odd. - */ - this_round = (this_round + 1) >> 1; - - while (this_round) { - *tmp_buf++ = vcs_scr_readw(vc, org++); - this_round --; - if (++col == maxcol) { - org = screen_pos(vc, p, viewed); - col = 0; - p += maxcol; - } - } - } + this_round = vcs_read_buf(vc, con_buf, pos, this_round, + viewed, &skip); } /* Finally, release the console semaphore while we push @@ -421,18 +453,18 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) */ console_unlock(); - ret = copy_to_user(buf, con_buf_start, orig_count); + ret = copy_to_user(buf, con_buf + skip, this_round); console_lock(); if (ret) { - read += (orig_count - ret); + read += this_round - ret; ret = -EFAULT; break; } - buf += orig_count; - pos += orig_count; - read += orig_count; - count -= orig_count; + buf += this_round; + pos += this_round; + read += this_round; + count -= this_round; } *ppos += read; if (read) @@ -443,18 +475,129 @@ unlock_out: return ret; } +static u16 *vcs_write_buf_noattr(struct vc_data *vc, const char *con_buf, + unsigned int pos, unsigned int count, bool viewed, u16 **org0) +{ + u16 *org; + unsigned int col, maxcol = vc->vc_cols; + + *org0 = org = screen_pos(vc, pos, viewed); + col = pos % maxcol; + pos += maxcol - col; + + while (count > 0) { + unsigned char c = *con_buf++; + + count--; + vcs_scr_writew(vc, + (vcs_scr_readw(vc, org) & 0xff00) | c, org); + org++; + if (++col == maxcol) { + org = screen_pos(vc, pos, viewed); + col = 0; + pos += maxcol; + } + } + + return org; +} + +/* + * Compilers (gcc 10) are unable to optimize the swap in cpu_to_le16. So do it + * the poor man way. + */ +static inline u16 vc_compile_le16(u8 hi, u8 lo) +{ +#ifdef __BIG_ENDIAN + return (lo << 8u) | hi; +#else + return (hi << 8u) | lo; +#endif +} + +static u16 *vcs_write_buf(struct vc_data *vc, const char *con_buf, + unsigned int pos, unsigned int count, bool viewed, u16 **org0) +{ + u16 *org; + unsigned int col, maxcol = vc->vc_cols; + unsigned char c; + + /* header */ + if (pos < HEADER_SIZE) { + char header[HEADER_SIZE]; + + getconsxy(vc, header + 2); + while (pos < HEADER_SIZE && count > 0) { + count--; + header[pos++] = *con_buf++; + } + if (!viewed) + putconsxy(vc, header + 2); + } + + if (!count) + return NULL; + + pos -= HEADER_SIZE; + col = (pos/2) % maxcol; + + *org0 = org = screen_pos(vc, pos/2, viewed); + + /* odd pos -- the first single character */ + if (pos & 1) { + count--; + c = *con_buf++; + vcs_scr_writew(vc, vc_compile_le16(c, vcs_scr_readw(vc, org)), + org); + org++; + pos++; + if (++col == maxcol) { + org = screen_pos(vc, pos/2, viewed); + col = 0; + } + } + + pos /= 2; + pos += maxcol - col; + + /* even pos -- handle attr+character pairs */ + while (count > 1) { + unsigned short w; + + w = get_unaligned(((unsigned short *)con_buf)); + vcs_scr_writew(vc, w, org++); + con_buf += 2; + count -= 2; + if (++col == maxcol) { + org = screen_pos(vc, pos, viewed); + col = 0; + pos += maxcol; + } + } + + if (!count) + return org; + + /* odd pos -- the remaining character */ + c = *con_buf++; + vcs_scr_writew(vc, vc_compile_le16(vcs_scr_readw(vc, org) >> 8, c), + org); + + return org; +} + static ssize_t 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; - long pos; - long attr, size, written; - char *con_buf0; - int col, maxcol, viewed; - u16 *org0 = NULL, *org = NULL; - size_t ret; char *con_buf; + u16 *org0, *org; + unsigned int written; + int size; + ssize_t ret; + loff_t pos; + bool viewed, attr; if (use_unicode(inode)) return -EOPNOTSUPP; @@ -476,7 +619,11 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) if (!vc) goto unlock_out; - size = vcs_size(inode); + size = vcs_size(vc, attr, false); + if (size < 0) { + ret = size; + goto unlock_out; + } ret = -EINVAL; if (pos < 0 || pos > size) goto unlock_out; @@ -484,9 +631,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) count = size - pos; written = 0; while (count) { - long this_round = count; - size_t orig_count; - long p; + unsigned int this_round = count; if (this_round > CON_BUF_SIZE) this_round = CON_BUF_SIZE; @@ -515,7 +660,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) * the user buffer, so recheck. * Return data written up to now on failure. */ - size = vcs_size(inode); + size = vcs_size(vc, attr, false); if (size < 0) { if (written) break; @@ -531,95 +676,18 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) * under the lock using the local kernel buffer. */ - con_buf0 = con_buf; - orig_count = this_round; - maxcol = vc->vc_cols; - p = pos; - if (!attr) { - org0 = org = screen_pos(vc, p, viewed); - col = p % maxcol; - p += maxcol - col; - - while (this_round > 0) { - unsigned char c = *con_buf0++; - - this_round--; - vcs_scr_writew(vc, - (vcs_scr_readw(vc, org) & 0xff00) | c, org); - org++; - if (++col == maxcol) { - org = screen_pos(vc, p, viewed); - col = 0; - p += maxcol; - } - } - } else { - if (p < HEADER_SIZE) { - char header[HEADER_SIZE]; - - getconsxy(vc, header + 2); - while (p < HEADER_SIZE && this_round > 0) { - this_round--; - header[p++] = *con_buf0++; - } - if (!viewed) - putconsxy(vc, header + 2); - } - p -= HEADER_SIZE; - col = (p/2) % maxcol; - if (this_round > 0) { - org0 = org = screen_pos(vc, p/2, viewed); - if ((p & 1) && this_round > 0) { - char c; - - this_round--; - c = *con_buf0++; -#ifdef __BIG_ENDIAN - vcs_scr_writew(vc, c | - (vcs_scr_readw(vc, org) & 0xff00), org); -#else - vcs_scr_writew(vc, (c << 8) | - (vcs_scr_readw(vc, org) & 0xff), org); -#endif - org++; - p++; - if (++col == maxcol) { - org = screen_pos(vc, p/2, viewed); - col = 0; - } - } - p /= 2; - p += maxcol - col; - } - while (this_round > 1) { - unsigned short w; - - w = get_unaligned(((unsigned short *)con_buf0)); - vcs_scr_writew(vc, w, org++); - con_buf0 += 2; - this_round -= 2; - if (++col == maxcol) { - org = screen_pos(vc, p, viewed); - col = 0; - p += maxcol; - } - } - if (this_round > 0) { - unsigned char c; - - c = *con_buf0++; -#ifdef __BIG_ENDIAN - vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org); -#else - vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org); -#endif - } - } - count -= orig_count; - written += orig_count; - buf += orig_count; - pos += orig_count; - if (org0) + if (attr) + org = vcs_write_buf(vc, con_buf, pos, this_round, + viewed, &org0); + else + org = vcs_write_buf_noattr(vc, con_buf, pos, this_round, + viewed, &org0); + + count -= this_round; + written += this_round; + buf += this_round; + pos += this_round; + if (org) update_region(vc, (unsigned long)(org0), org - org0); } *ppos += written; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index ccb533fd00a2..d04a162939a4 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -283,7 +283,8 @@ static inline bool con_should_update(const struct vc_data *vc) return con_is_visible(vc) && !console_blanked; } -static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) +static inline unsigned short *screenpos(const struct vc_data *vc, int offset, + bool viewed) { unsigned short *p; @@ -543,7 +544,7 @@ int vc_uniscr_check(struct vc_data *vc) * This must be preceded by a successful call to vc_uniscr_check() once * the console lock has been taken. */ -void vc_uniscr_copy_line(struct vc_data *vc, void *dest, int viewed, +void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed, unsigned int row, unsigned int col, unsigned int nr) { struct uni_screen *uniscr = get_vc_uniscr(vc); @@ -752,7 +753,7 @@ static void update_attr(struct vc_data *vc) } /* Note: inverting the screen twice should revert to the original state */ -void invert_screen(struct vc_data *vc, int offset, int count, int viewed) +void invert_screen(struct vc_data *vc, int offset, int count, bool viewed) { unsigned short *p; @@ -811,7 +812,7 @@ void complement_pos(struct vc_data *vc, int offset) if (old_offset != -1 && old_offset >= 0 && old_offset < vc->vc_screenbuf_size) { - scr_writew(old, screenpos(vc, old_offset, 1)); + scr_writew(old, screenpos(vc, old_offset, true)); if (con_should_update(vc)) vc->vc_sw->con_putc(vc, old, oldy, oldx); notify_update(vc); @@ -823,7 +824,7 @@ void complement_pos(struct vc_data *vc, int offset) offset < vc->vc_screenbuf_size) { unsigned short new; unsigned short *p; - p = screenpos(vc, offset, 1); + p = screenpos(vc, offset, true); old = scr_readw(p); new = old ^ vc->vc_complement_mask; scr_writew(new, p); @@ -1180,7 +1181,6 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, /** * vc_do_resize - resizing method for the tty * @tty: tty being resized - * @real_tty: real tty (different to tty if a pty/tty pair) * @vc: virtual console private data * @cols: columns * @lines: lines @@ -1201,7 +1201,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, unsigned int old_rows, old_row_size, first_copied_row; unsigned int new_cols, new_rows, new_row_size, new_screen_size; unsigned int user; - unsigned short *newscreen; + unsigned short *oldscreen, *newscreen; struct uni_screen *new_uniscr = NULL; WARN_CONSOLE_UNLOCKED(); @@ -1299,10 +1299,11 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, if (new_scr_end > new_origin) scr_memsetw((void *)new_origin, vc->vc_video_erase_char, new_scr_end - new_origin); - kfree(vc->vc_screenbuf); + oldscreen = vc->vc_screenbuf; vc->vc_screenbuf = newscreen; vc->vc_screenbuf_size = new_screen_size; set_origin(vc); + kfree(oldscreen); /* do part of a reset_terminal() */ vc->vc_top = 0; @@ -1553,7 +1554,7 @@ static void csi_J(struct vc_data *vc, int vpar) break; case 3: /* include scrollback */ flush_scrollback(vc); - /* fallthrough */ + fallthrough; case 2: /* erase whole display */ vc_uniscr_clear_lines(vc, 0, vc->vc_rows); count = vc->vc_cols * vc->vc_rows; @@ -1884,7 +1885,9 @@ static void set_mode(struct vc_data *vc, int on_off) case 5: /* Inverted screen on/off */ if (vc->vc_decscnm != on_off) { vc->vc_decscnm = on_off; - invert_screen(vc, 0, vc->vc_screenbuf_size, 0); + invert_screen(vc, 0, + vc->vc_screenbuf_size, + false); update_attr(vc); } break; @@ -2167,7 +2170,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) lf(vc); if (!is_kbd(vc, lnm)) return; - /* fall through */ + fallthrough; case 13: cr(vc); return; @@ -2306,7 +2309,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) return; } vc->vc_priv = EPecma; - /* fall through */ + fallthrough; case ESgetpars: if (c == ';' && vc->vc_npar < NPAR - 1) { vc->vc_npar++; @@ -2604,6 +2607,9 @@ static inline int vc_sanitize_unicode(const int c) /** * vc_translate_unicode -- Combine UTF-8 into Unicode in @vc_utf_char + * @vc: virtual console + * @c: character to translate + * @rescan: we return true if we need more (continuation) data * * @vc_utf_char is the being-constructed unicode character. * @vc_utf_count is the number of continuation bytes still expected to arrive. @@ -3979,7 +3985,7 @@ EXPORT_SYMBOL(con_is_visible); /** * con_debug_enter - prepare the console for the kernel debugger - * @sw: console driver + * @vc: virtual console * * Called when the console is taken over by the kernel debugger, this * function needs to save the current console state, then put the console @@ -4037,7 +4043,6 @@ EXPORT_SYMBOL_GPL(con_debug_enter); /** * con_debug_leave - restore console state - * @sw: console driver * * Restore the console state to what it was before the kernel debugger * was invoked. @@ -4699,27 +4704,6 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) return rc; } -static int con_font_copy(struct vc_data *vc, struct console_font_op *op) -{ - int con = op->height; - int rc; - - - console_lock(); - if (vc->vc_mode != KD_TEXT) - rc = -EINVAL; - else if (!vc->vc_sw->con_font_copy) - rc = -ENOSYS; - else if (con < 0 || !vc_cons_allocated(con)) - rc = -ENOTTY; - else if (con == vc->vc_num) /* nothing to do */ - rc = 0; - else - rc = vc->vc_sw->con_font_copy(vc, con); - console_unlock(); - return rc; -} - int con_font_op(struct vc_data *vc, struct console_font_op *op) { switch (op->op) { @@ -4730,7 +4714,8 @@ int con_font_op(struct vc_data *vc, struct console_font_op *op) case KD_FONT_OP_SET_DEFAULT: return con_font_default(vc, op); case KD_FONT_OP_COPY: - return con_font_copy(vc, op); + /* was buggy and never really used */ + return -EINVAL; } return -ENOSYS; } @@ -4740,9 +4725,9 @@ int con_font_op(struct vc_data *vc, struct console_font_op *op) */ /* used by selection */ -u16 screen_glyph(struct vc_data *vc, int offset) +u16 screen_glyph(const struct vc_data *vc, int offset) { - u16 w = scr_readw(screenpos(vc, offset, 1)); + u16 w = scr_readw(screenpos(vc, offset, true)); u16 c = w & 0xff; if (w & vc->vc_hi_font_mask) @@ -4751,7 +4736,7 @@ u16 screen_glyph(struct vc_data *vc, int offset) } EXPORT_SYMBOL_GPL(screen_glyph); -u32 screen_glyph_unicode(struct vc_data *vc, int n) +u32 screen_glyph_unicode(const struct vc_data *vc, int n) { struct uni_screen *uniscr = get_vc_uniscr(vc); @@ -4762,27 +4747,27 @@ u32 screen_glyph_unicode(struct vc_data *vc, int n) EXPORT_SYMBOL_GPL(screen_glyph_unicode); /* used by vcs - note the word offset */ -unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed) +unsigned short *screen_pos(const struct vc_data *vc, int w_offset, bool viewed) { return screenpos(vc, 2 * w_offset, viewed); } EXPORT_SYMBOL_GPL(screen_pos); -void getconsxy(struct vc_data *vc, unsigned char *p) +void getconsxy(const struct vc_data *vc, unsigned char xy[static 2]) { /* clamp values if they don't fit */ - p[0] = min(vc->state.x, 0xFFu); - p[1] = min(vc->state.y, 0xFFu); + xy[0] = min(vc->state.x, 0xFFu); + xy[1] = min(vc->state.y, 0xFFu); } -void putconsxy(struct vc_data *vc, unsigned char *p) +void putconsxy(struct vc_data *vc, unsigned char xy[static const 2]) { hide_cursor(vc); - gotoxy(vc, p[0], p[1]); + gotoxy(vc, xy[0], xy[1]); set_cursor(vc); } -u16 vcs_scr_readw(struct vc_data *vc, const u16 *org) +u16 vcs_scr_readw(const struct vc_data *vc, const u16 *org) { if ((unsigned long)org == vc->vc_pos && softcursor_original != -1) return softcursor_original; diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 91c301775047..5f61b25a9aaa 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -181,7 +181,7 @@ static void vt_event_wait(struct vt_event_wait *vw) /** * vt_event_wait_ioctl - event ioctl handler - * @arg: argument to ioctl + * @event: argument to ioctl (the event) * * Implement the VT_WAITEVENT ioctl using the VT event interface */ @@ -208,7 +208,6 @@ static int vt_event_wait_ioctl(struct vt_event __user *event) /** * vt_waitactive - active console wait - * @event: event code * @n: new console * * Helper for event waits. Used to implement the legacy @@ -485,7 +484,7 @@ static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd, return 0; } -static inline int do_fontx_ioctl(int cmd, +static inline int do_fontx_ioctl(struct vc_data *vc, int cmd, struct consolefontdesc __user *user_cfd, struct console_font_op *op) { @@ -503,15 +502,16 @@ static inline int do_fontx_ioctl(int cmd, op->height = cfdarg.charheight; op->charcount = cfdarg.charcount; op->data = cfdarg.chardata; - return con_font_op(vc_cons[fg_console].d, op); - case GIO_FONTX: { + return con_font_op(vc, op); + + case GIO_FONTX: op->op = KD_FONT_OP_GET; op->flags = KD_FONT_FLAG_OLD; op->width = 8; op->height = cfdarg.charheight; op->charcount = cfdarg.charcount; op->data = cfdarg.chardata; - i = con_font_op(vc_cons[fg_console].d, op); + i = con_font_op(vc, op); if (i) return i; cfdarg.charheight = op->height; @@ -519,12 +519,11 @@ static inline int do_fontx_ioctl(int cmd, if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) return -EFAULT; return 0; - } } return -EINVAL; } -static int vt_io_fontreset(struct console_font_op *op) +static int vt_io_fontreset(struct vc_data *vc, struct console_font_op *op) { int ret; @@ -538,19 +537,19 @@ static int vt_io_fontreset(struct console_font_op *op) op->op = KD_FONT_OP_SET_DEFAULT; op->data = NULL; - ret = con_font_op(vc_cons[fg_console].d, op); + ret = con_font_op(vc, op); if (ret) return ret; console_lock(); - con_set_default_unimap(vc_cons[fg_console].d); + con_set_default_unimap(vc); console_unlock(); return 0; } static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, - struct vc_data *vc) + bool perm, struct vc_data *vc) { struct unimapdesc tmp; @@ -558,9 +557,11 @@ static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, return -EFAULT; switch (cmd) { case PIO_UNIMAP: + if (!perm) + return -EPERM; return con_set_unimap(vc, tmp.entry_ct, tmp.entries); case GIO_UNIMAP: - if (fg_console != vc->vc_num) + if (!perm && fg_console != vc->vc_num) return -EPERM; return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); @@ -583,7 +584,7 @@ static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up, op.height = 0; op.charcount = 256; op.data = up; - return con_font_op(vc_cons[fg_console].d, &op); + return con_font_op(vc, &op); case GIO_FONT: op.op = KD_FONT_OP_GET; @@ -592,7 +593,7 @@ static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up, op.height = 32; op.charcount = 256; op.data = up; - return con_font_op(vc_cons[fg_console].d, &op); + return con_font_op(vc, &op); case PIO_CMAP: if (!perm) @@ -608,13 +609,13 @@ static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up, fallthrough; case GIO_FONTX: - return do_fontx_ioctl(cmd, up, &op); + return do_fontx_ioctl(vc, cmd, up, &op); case PIO_FONTRESET: if (!perm) return -EPERM; - return vt_io_fontreset(&op); + return vt_io_fontreset(vc, &op); case PIO_SCRNMAP: if (!perm) @@ -640,10 +641,7 @@ static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up, case PIO_UNIMAP: case GIO_UNIMAP: - if (!perm) - return -EPERM; - - return do_unimap_ioctl(cmd, up, vc); + return do_unimap_ioctl(cmd, up, perm, vc); default: return -ENOIOCTLCMD; @@ -773,48 +771,21 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs) if (copy_from_user(&v, cs, sizeof(struct vt_consize))) return -EFAULT; - /* FIXME: Should check the copies properly */ - if (!v.v_vlin) - v.v_vlin = vc->vc_scan_lines; - - if (v.v_clin) { - int rows = v.v_vlin / v.v_clin; - if (v.v_rows != rows) { - if (v.v_rows) /* Parameters don't add up */ - return -EINVAL; - v.v_rows = rows; - } - } - - if (v.v_vcol && v.v_ccol) { - int cols = v.v_vcol / v.v_ccol; - if (v.v_cols != cols) { - if (v.v_cols) - return -EINVAL; - v.v_cols = cols; - } - } - - if (v.v_clin > 32) - return -EINVAL; + if (v.v_vlin) + pr_info_once("\"struct vt_consize\"->v_vlin is ignored. Please report if you need this.\n"); + if (v.v_clin) + pr_info_once("\"struct vt_consize\"->v_clin is ignored. Please report if you need this.\n"); + console_lock(); for (i = 0; i < MAX_NR_CONSOLES; i++) { - struct vc_data *vcp; + vc = vc_cons[i].d; - if (!vc_cons[i].d) - continue; - console_lock(); - vcp = vc_cons[i].d; - if (vcp) { - if (v.v_vlin) - vcp->vc_scan_lines = v.v_vlin; - if (v.v_clin) - vcp->vc_font.height = v.v_clin; - vcp->vc_resize_user = 1; - vc_resize(vcp, v.v_cols, v.v_rows); + if (vc) { + vc->vc_resize_user = 1; + vc_resize(vc, v.v_cols, v.v_rows); } - console_unlock(); } + console_unlock(); return 0; } @@ -1095,8 +1066,9 @@ struct compat_consolefontdesc { }; static inline int -compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd, - int perm, struct console_font_op *op) +compat_fontx_ioctl(struct vc_data *vc, int cmd, + struct compat_consolefontdesc __user *user_cfd, + int perm, struct console_font_op *op) { struct compat_consolefontdesc cfdarg; int i; @@ -1114,7 +1086,8 @@ compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd, op->height = cfdarg.charheight; op->charcount = cfdarg.charcount; op->data = compat_ptr(cfdarg.chardata); - return con_font_op(vc_cons[fg_console].d, op); + return con_font_op(vc, op); + case GIO_FONTX: op->op = KD_FONT_OP_GET; op->flags = KD_FONT_FLAG_OLD; @@ -1122,7 +1095,7 @@ compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd, op->height = cfdarg.charheight; op->charcount = cfdarg.charcount; op->data = compat_ptr(cfdarg.chardata); - i = con_font_op(vc_cons[fg_console].d, op); + i = con_font_op(vc, op); if (i) return i; cfdarg.charheight = op->height; @@ -1212,7 +1185,7 @@ long vt_compat_ioctl(struct tty_struct *tty, */ case PIO_FONTX: case GIO_FONTX: - return compat_fontx_ioctl(cmd, up, perm, &op); + return compat_fontx_ioctl(vc, cmd, up, perm, &op); case KDFONTOP: return compat_kdfontop_ioctl(up, perm, &op, vc); |