TTY/Serial/Console fixes for 6.10-rc6

Here are a bunch of fixes/reverts for 6.10-rc6.  Include in here are:
   - revert the bunch of tty/serial/console changes that landed in -rc1
     that didn't quite work properly yet.  Everyone agreed to just revert
     them for now and will work on making them better for a future
     release instead of trying to quick fix the existing changes this
     late in the release cycle
   - 8250 driver port count bugfix
   - Other tiny serial port bugfixes for reported issues
 
 All of these have been in linux-next this week with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZoFmvg8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ymziACgvoDTxuDHHfPOd6h/1qrHqYpFK1YAn2IDMJGj
 Ng4/I/gwnkJeeHQC5JSn
 =g9o4
 -----END PGP SIGNATURE-----

Merge tag 'tty-6.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty / serial / console fixes from Greg KH:
 "Here are a bunch of fixes/reverts for 6.10-rc6.  Include in here are:

   - revert the bunch of tty/serial/console changes that landed in -rc1
     that didn't quite work properly yet.

     Everyone agreed to just revert them for now and will work on making
     them better for a future release instead of trying to quick fix the
     existing changes this late in the release cycle

   - 8250 driver port count bugfix

   - Other tiny serial port bugfixes for reported issues

  All of these have been in linux-next this week with no reported
  issues"

* tag 'tty-6.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  Revert "printk: Save console options for add_preferred_console_match()"
  Revert "printk: Don't try to parse DEVNAME:0.0 console options"
  Revert "printk: Flag register_console() if console is set on command line"
  Revert "serial: core: Add support for DEVNAME:0.0 style naming for kernel console"
  Revert "serial: core: Handle serial console options"
  Revert "serial: 8250: Add preferred console in serial8250_isa_init_ports()"
  Revert "Documentation: kernel-parameters: Add DEVNAME:0.0 format for serial ports"
  Revert "serial: 8250: Fix add preferred console for serial8250_isa_init_ports()"
  Revert "serial: core: Fix ifdef for serial base console functions"
  serial: bcm63xx-uart: fix tx after conversion to uart_port_tx_limited()
  serial: core: introduce uart_port_tx_limited_flags()
  Revert "serial: core: only stop transmit when HW fifo is empty"
  serial: imx: set receiver level before starting uart
  tty: mcf: MCF54418 has 10 UARTS
  serial: 8250_omap: Implementation of Errata i2310
  tty: serial: 8250: Fix port count mismatch with the device
This commit is contained in:
Linus Torvalds 2024-06-30 08:57:43 -07:00
commit 3e334486ec
16 changed files with 65 additions and 374 deletions

View File

@ -788,25 +788,6 @@
Documentation/networking/netconsole.rst for an
alternative.
<DEVNAME>:<n>.<n>[,options]
Use the specified serial port on the serial core bus.
The addressing uses DEVNAME of the physical serial port
device, followed by the serial core controller instance,
and the serial port instance. The options are the same
as documented for the ttyS addressing above.
The mapping of the serial ports to the tty instances
can be viewed with:
$ ls -d /sys/bus/serial-base/devices/*:*.*/tty/*
/sys/bus/serial-base/devices/00:04:0.0/tty/ttyS0
In the above example, the console can be addressed with
console=00:04:0.0. Note that a console addressed this
way will only get added when the related device driver
is ready. The use of an earlycon parameter in addition to
the console may be desired for console output early on.
uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options]
uart[8250],mmio16,<addr>[,options]

View File

@ -15,7 +15,6 @@
*/
#include <linux/acpi.h>
#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
@ -42,8 +41,6 @@
#include <asm/irq.h>
#include "../serial_base.h" /* For serial_base_add_isa_preferred_console() */
#include "8250.h"
/*
@ -563,8 +560,6 @@ static void __init serial8250_isa_init_ports(void)
port->irqflags |= irqflag;
if (serial8250_isa_config != NULL)
serial8250_isa_config(i, &up->port, &up->capabilities);
serial_base_add_isa_preferred_console(serial8250_reg.dev_name, i);
}
}

View File

@ -115,6 +115,10 @@
/* RX FIFO occupancy indicator */
#define UART_OMAP_RX_LVL 0x19
/* Timeout low and High */
#define UART_OMAP_TO_L 0x26
#define UART_OMAP_TO_H 0x27
/*
* Copy of the genpd flags for the console.
* Only used if console suspend is disabled
@ -663,13 +667,24 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
/*
* On K3 SoCs, it is observed that RX TIMEOUT is signalled after
* FIFO has been drained, in which case a dummy read of RX FIFO
* is required to clear RX TIMEOUT condition.
* FIFO has been drained or erroneously.
* So apply solution of Errata i2310 as mentioned in
* https://www.ti.com/lit/pdf/sprz536
*/
if (priv->habit & UART_RX_TIMEOUT_QUIRK &&
(iir & UART_IIR_RX_TIMEOUT) == UART_IIR_RX_TIMEOUT &&
serial_port_in(port, UART_OMAP_RX_LVL) == 0) {
serial_port_in(port, UART_RX);
(iir & UART_IIR_RX_TIMEOUT) == UART_IIR_RX_TIMEOUT) {
unsigned char efr2, timeout_h, timeout_l;
efr2 = serial_in(up, UART_OMAP_EFR2);
timeout_h = serial_in(up, UART_OMAP_TO_H);
timeout_l = serial_in(up, UART_OMAP_TO_L);
serial_out(up, UART_OMAP_TO_H, 0xFF);
serial_out(up, UART_OMAP_TO_L, 0xFF);
serial_out(up, UART_OMAP_EFR2, UART_OMAP_EFR2_TIMEOUT_BEHAVE);
serial_in(up, UART_IIR);
serial_out(up, UART_OMAP_EFR2, efr2);
serial_out(up, UART_OMAP_TO_H, timeout_h);
serial_out(up, UART_OMAP_TO_L, timeout_l);
}
/* Stop processing interrupts on input overrun */

View File

@ -1985,6 +1985,17 @@ enum {
MOXA_SUPP_RS485 = BIT(2),
};
static unsigned short moxa_get_nports(unsigned short device)
{
switch (device) {
case PCI_DEVICE_ID_MOXA_CP116E_A_A:
case PCI_DEVICE_ID_MOXA_CP116E_A_B:
return 8;
}
return FIELD_GET(0x00F0, device);
}
static bool pci_moxa_is_mini_pcie(unsigned short device)
{
if (device == PCI_DEVICE_ID_MOXA_CP102N ||
@ -2038,7 +2049,7 @@ static int pci_moxa_init(struct pci_dev *dev)
{
unsigned short device = dev->device;
resource_size_t iobar_addr = pci_resource_start(dev, 2);
unsigned int num_ports = (device & 0x00F0) >> 4, i;
unsigned int i, num_ports = moxa_get_nports(device);
u8 val, init_mode = MOXA_RS232;
if (!(pci_moxa_supported_rs(dev) & MOXA_SUPP_RS232)) {

View File

@ -308,8 +308,8 @@ static void bcm_uart_do_tx(struct uart_port *port)
val = bcm_uart_readl(port, UART_MCTL_REG);
val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT;
pending = uart_port_tx_limited(port, ch, port->fifosize - val,
pending = uart_port_tx_limited_flags(port, ch, UART_TX_NOSTOP,
port->fifosize - val,
true,
bcm_uart_writel(port, ch, UART_FIFO_REG),
({}));
@ -320,6 +320,9 @@ static void bcm_uart_do_tx(struct uart_port *port)
val = bcm_uart_readl(port, UART_IR_REG);
val &= ~UART_TX_INT_MASK;
bcm_uart_writel(port, val, UART_IR_REG);
if (uart_tx_stopped(port))
bcm_uart_stop_tx(port);
}
/*

View File

@ -1952,8 +1952,10 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
/* Make sure Rx is enabled in case Tx is active with Rx disabled */
if (!(rs485conf->flags & SER_RS485_ENABLED) ||
rs485conf->flags & SER_RS485_RX_DURING_TX)
rs485conf->flags & SER_RS485_RX_DURING_TX) {
imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
imx_uart_start_rx(port);
}
return 0;
}

View File

@ -462,7 +462,7 @@ static const struct uart_ops mcf_uart_ops = {
.verify_port = mcf_verify_port,
};
static struct mcf_uart mcf_ports[4];
static struct mcf_uart mcf_ports[10];
#define MCF_MAXPORTS ARRAY_SIZE(mcf_ports)

View File

@ -49,33 +49,3 @@ void serial_ctrl_unregister_port(struct uart_driver *drv, struct uart_port *port
int serial_core_register_port(struct uart_driver *drv, struct uart_port *port);
void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port);
#ifdef CONFIG_SERIAL_CORE_CONSOLE
int serial_base_add_preferred_console(struct uart_driver *drv,
struct uart_port *port);
#else
static inline
int serial_base_add_preferred_console(struct uart_driver *drv,
struct uart_port *port)
{
return 0;
}
#endif
#ifdef CONFIG_SERIAL_8250_CONSOLE
int serial_base_add_isa_preferred_console(const char *name, int idx);
#else
static inline
int serial_base_add_isa_preferred_console(const char *name, int idx)
{
return 0;
}
#endif

View File

@ -8,7 +8,6 @@
* The serial core bus manages the serial core controller instances.
*/
#include <linux/cleanup.h>
#include <linux/container_of.h>
#include <linux/device.h>
#include <linux/idr.h>
@ -205,134 +204,6 @@ void serial_base_port_device_remove(struct serial_port_device *port_dev)
put_device(&port_dev->dev);
}
#ifdef CONFIG_SERIAL_CORE_CONSOLE
static int serial_base_add_one_prefcon(const char *match, const char *dev_name,
int port_id)
{
int ret;
ret = add_preferred_console_match(match, dev_name, port_id);
if (ret == -ENOENT)
return 0;
return ret;
}
#ifdef __sparc__
/* Handle Sparc ttya and ttyb options as done in console_setup() */
static int serial_base_add_sparc_console(const char *dev_name, int idx)
{
const char *name;
switch (idx) {
case 0:
name = "ttya";
break;
case 1:
name = "ttyb";
break;
default:
return 0;
}
return serial_base_add_one_prefcon(name, dev_name, idx);
}
#else
static inline int serial_base_add_sparc_console(const char *dev_name, int idx)
{
return 0;
}
#endif
static int serial_base_add_prefcon(const char *name, int idx)
{
const char *char_match __free(kfree) = NULL;
const char *nmbr_match __free(kfree) = NULL;
int ret;
/* Handle ttyS specific options */
if (strstarts(name, "ttyS")) {
/* No name, just a number */
nmbr_match = kasprintf(GFP_KERNEL, "%i", idx);
if (!nmbr_match)
return -ENODEV;
ret = serial_base_add_one_prefcon(nmbr_match, name, idx);
if (ret)
return ret;
/* Sparc ttya and ttyb */
ret = serial_base_add_sparc_console(name, idx);
if (ret)
return ret;
}
/* Handle the traditional character device name style console=ttyS0 */
char_match = kasprintf(GFP_KERNEL, "%s%i", name, idx);
if (!char_match)
return -ENOMEM;
return serial_base_add_one_prefcon(char_match, name, idx);
}
/**
* serial_base_add_preferred_console - Adds a preferred console
* @drv: Serial port device driver
* @port: Serial port instance
*
* Tries to add a preferred console for a serial port if specified in the
* kernel command line. Supports both the traditional character device such
* as console=ttyS0, and a hardware addressing based console=DEVNAME:0.0
* style name.
*
* Translates the kernel command line option using a hardware based addressing
* console=DEVNAME:0.0 to the serial port character device such as ttyS0.
* Cannot be called early for ISA ports, depends on struct device.
*
* Note that duplicates are ignored by add_preferred_console().
*
* Return: 0 on success, negative error code on failure.
*/
int serial_base_add_preferred_console(struct uart_driver *drv,
struct uart_port *port)
{
const char *port_match __free(kfree) = NULL;
int ret;
ret = serial_base_add_prefcon(drv->dev_name, port->line);
if (ret)
return ret;
port_match = kasprintf(GFP_KERNEL, "%s:%i.%i", dev_name(port->dev),
port->ctrl_id, port->port_id);
if (!port_match)
return -ENOMEM;
/* Translate a hardware addressing style console=DEVNAME:0.0 */
return serial_base_add_one_prefcon(port_match, drv->dev_name, port->line);
}
#endif
#ifdef CONFIG_SERIAL_8250_CONSOLE
/*
* Early ISA ports initialize the console before there is no struct device.
* This should be only called from serial8250_isa_init_preferred_console(),
* other callers are likely wrong and should rely on earlycon instead.
*/
int serial_base_add_isa_preferred_console(const char *name, int idx)
{
return serial_base_add_prefcon(name, idx);
}
#endif
static int serial_base_init(void)
{
int ret;

View File

@ -3422,10 +3422,6 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port)
if (ret)
goto err_unregister_ctrl_dev;
ret = serial_base_add_preferred_console(drv, port);
if (ret)
goto err_unregister_port_dev;
ret = serial_core_add_one_port(drv, port);
if (ret)
goto err_unregister_port_dev;

View File

@ -60,9 +60,6 @@ static inline const char *printk_skip_headers(const char *buffer)
#define CONSOLE_LOGLEVEL_DEFAULT CONFIG_CONSOLE_LOGLEVEL_DEFAULT
#define CONSOLE_LOGLEVEL_QUIET CONFIG_CONSOLE_LOGLEVEL_QUIET
int add_preferred_console_match(const char *match, const char *name,
const short idx);
extern int console_printk[];
#define console_loglevel (console_printk[0])

View File

@ -811,8 +811,7 @@ enum UART_TX_FLAGS {
if (pending < WAKEUP_CHARS) { \
uart_write_wakeup(__port); \
\
if (!((flags) & UART_TX_NOSTOP) && pending == 0 && \
__port->ops->tx_empty(__port)) \
if (!((flags) & UART_TX_NOSTOP) && pending == 0) \
__port->ops->stop_tx(__port); \
} \
\
@ -851,6 +850,24 @@ enum UART_TX_FLAGS {
__count--); \
})
/**
* uart_port_tx_limited_flags -- transmit helper for uart_port with count limiting with flags
* @port: uart port
* @ch: variable to store a character to be written to the HW
* @flags: %UART_TX_NOSTOP or similar
* @count: a limit of characters to send
* @tx_ready: can HW accept more data function
* @put_char: function to write a character
* @tx_done: function to call after the loop is done
*
* See uart_port_tx_limited() for more details.
*/
#define uart_port_tx_limited_flags(port, ch, flags, count, tx_ready, put_char, tx_done) ({ \
unsigned int __count = (count); \
__uart_port_tx(port, ch, flags, tx_ready, put_char, tx_done, __count, \
__count--); \
})
/**
* uart_port_tx -- transmit helper for uart_port
* @port: uart port

View File

@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y = printk.o conopt.o
obj-y = printk.o
obj-$(CONFIG_PRINTK) += printk_safe.o nbcon.o
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
obj-$(CONFIG_PRINTK_INDEX) += index.o

View File

@ -1,146 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Kernel command line console options for hardware based addressing
*
* Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
* Author: Tony Lindgren <tony@atomide.com>
*/
#include <linux/console.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/types.h>
#include <asm/errno.h>
#include "console_cmdline.h"
/*
* Allow longer DEVNAME:0.0 style console naming such as abcd0000.serial:0.0
* in addition to the legacy ttyS0 style naming.
*/
#define CONSOLE_NAME_MAX 32
#define CONSOLE_OPT_MAX 16
#define CONSOLE_BRL_OPT_MAX 16
struct console_option {
char name[CONSOLE_NAME_MAX];
char opt[CONSOLE_OPT_MAX];
char brl_opt[CONSOLE_BRL_OPT_MAX];
u8 has_brl_opt:1;
};
/* Updated only at console_setup() time, no locking needed */
static struct console_option conopt[MAX_CMDLINECONSOLES];
/**
* console_opt_save - Saves kernel command line console option for driver use
* @str: Kernel command line console name and option
* @brl_opt: Braille console options
*
* Saves a kernel command line console option for driver subsystems to use for
* adding a preferred console during init. Called from console_setup() only.
*
* Return: 0 on success, negative error code on failure.
*/
int __init console_opt_save(const char *str, const char *brl_opt)
{
struct console_option *con;
size_t namelen, optlen;
const char *opt;
int i;
namelen = strcspn(str, ",");
if (namelen == 0 || namelen >= CONSOLE_NAME_MAX)
return -EINVAL;
opt = str + namelen;
if (*opt == ',')
opt++;
optlen = strlen(opt);
if (optlen >= CONSOLE_OPT_MAX)
return -EINVAL;
for (i = 0; i < MAX_CMDLINECONSOLES; i++) {
con = &conopt[i];
if (con->name[0]) {
if (!strncmp(str, con->name, namelen))
return 0;
continue;
}
/*
* The name isn't terminated, only opt is. Empty opt is fine,
* but brl_opt can be either empty or NULL. For more info, see
* _braille_console_setup().
*/
strscpy(con->name, str, namelen + 1);
strscpy(con->opt, opt, CONSOLE_OPT_MAX);
if (brl_opt) {
strscpy(con->brl_opt, brl_opt, CONSOLE_BRL_OPT_MAX);
con->has_brl_opt = 1;
}
return 0;
}
return -ENOMEM;
}
static struct console_option *console_opt_find(const char *name)
{
struct console_option *con;
int i;
for (i = 0; i < MAX_CMDLINECONSOLES; i++) {
con = &conopt[i];
if (!strcmp(name, con->name))
return con;
}
return NULL;
}
/**
* add_preferred_console_match - Adds a preferred console if a match is found
* @match: Expected console on kernel command line, such as console=DEVNAME:0.0
* @name: Name of the console character device to add such as ttyS
* @idx: Index for the console
*
* Allows driver subsystems to add a console after translating the command
* line name to the character device name used for the console. Options are
* added automatically based on the kernel command line. Duplicate preferred
* consoles are ignored by __add_preferred_console().
*
* Return: 0 on success, negative error code on failure.
*/
int add_preferred_console_match(const char *match, const char *name,
const short idx)
{
struct console_option *con;
char *brl_opt = NULL;
if (!match || !strlen(match) || !name || !strlen(name) ||
idx < 0)
return -EINVAL;
con = console_opt_find(match);
if (!con)
return -ENOENT;
/*
* See __add_preferred_console(). It checks for NULL brl_options to set
* the preferred_console flag. Empty brl_opt instead of NULL leads into
* the preferred_console flag not set, and CON_CONSDEV not being set,
* and the boot console won't get disabled at the end of console_setup().
*/
if (con->has_brl_opt)
brl_opt = con->brl_opt;
console_opt_add_preferred_console(name, idx, con->opt, brl_opt);
return 0;
}

View File

@ -2,12 +2,6 @@
#ifndef _CONSOLE_CMDLINE_H
#define _CONSOLE_CMDLINE_H
#define MAX_CMDLINECONSOLES 8
int console_opt_save(const char *str, const char *brl_opt);
int console_opt_add_preferred_console(const char *name, const short idx,
char *options, char *brl_options);
struct console_cmdline
{
char name[16]; /* Name of the driver */

View File

@ -383,6 +383,9 @@ static int console_locked;
/*
* Array of consoles built from command line options (console=)
*/
#define MAX_CMDLINECONSOLES 8
static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
static int preferred_console = -1;
@ -2500,17 +2503,6 @@ static int __init console_setup(char *str)
if (_braille_console_setup(&str, &brl_options))
return 1;
/* Save the console for driver subsystem use */
if (console_opt_save(str, brl_options))
return 1;
/* Flag register_console() to not call try_enable_default_console() */
console_set_on_cmdline = 1;
/* Don't attempt to parse a DEVNAME:0.0 style console */
if (strchr(str, ':'))
return 1;
/*
* Decode str into name, index, options.
*/
@ -2541,13 +2533,6 @@ static int __init console_setup(char *str)
}
__setup("console=", console_setup);
/* Only called from add_preferred_console_match() */
int console_opt_add_preferred_console(const char *name, const short idx,
char *options, char *brl_options)
{
return __add_preferred_console(name, idx, options, brl_options, true);
}
/**
* add_preferred_console - add a device to the list of preferred consoles.
* @name: device name
@ -3522,7 +3507,7 @@ void register_console(struct console *newcon)
* Note that a console with tty binding will have CON_CONSDEV
* flag set and will be first in the list.
*/
if (preferred_console < 0 && !console_set_on_cmdline) {
if (preferred_console < 0) {
if (hlist_empty(&console_list) || !console_first()->device ||
console_first()->flags & CON_BOOT) {
try_enable_default_console(newcon);