Commit 9d86719f authored by Tony Lindgren's avatar Tony Lindgren Committed by Greg Kroah-Hartman
Browse files

serial: 8250: Allow using ports higher than SERIAL_8250_RUNTIME_UARTS



We already allocate CONFIG_SERIAL_8250_NR_UARTS, but only allow using
CONFIG_SERIAL_8250_RUNTIME_UARTS uarts unless nr_uarts module params
is set. This causes issues for using distro kernels on SoCs with a
large number of serial ports.

Let's allow up to CONFIG_SERIAL_8250_NR_UARTS instead. To do this, we init
the ports as needed if the initial uarts was too low. This way there's no
need to set the value for CONFIG_SERIAL_8250_RUNTIME_UARTS to some SoC
specific higher value. Typically the default value of 4 can be used as
set for legacy reasons.

Note that limiting the number of intial uarts still works as before
unless a serial console on a higher port is specified. In this case we
will increase the nr_ports up to the console port specified.

Suggested-by: default avatarAndrew Davis <afd@ti.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
Link: https://lore.kernel.org/r/20230508111903.39339-1-tony@atomide.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent db86bb6e
Loading
Loading
Loading
Loading
+63 −23
Original line number Diff line number Diff line
@@ -488,28 +488,20 @@ static inline void serial8250_apply_quirks(struct uart_8250_port *up)
	up->port.quirks |= skip_txen_test ? UPQ_NO_TXEN_TEST : 0;
}

static void __init serial8250_isa_init_ports(void)
static struct uart_8250_port *serial8250_setup_port(int index)
{
	struct uart_8250_port *up;
	static int first = 1;
	int i, irqflag = 0;

	if (!first)
		return;
	first = 0;

	if (nr_uarts > UART_NR)
		nr_uarts = UART_NR;
	if (index >= UART_NR)
		return NULL;

	for (i = 0; i < nr_uarts; i++) {
		struct uart_8250_port *up = &serial8250_ports[i];
		struct uart_port *port = &up->port;
	up = &serial8250_ports[index];
	up->port.line = index;

		port->line = i;
	serial8250_init_port(up);
	if (!base_ops)
			base_ops = port->ops;
		port->ops = &univ8250_port_ops;
		base_ops = up->port.ops;
	up->port.ops = &univ8250_port_ops;

	timer_setup(&up->timer, serial8250_timeout, 0);

@@ -517,11 +509,34 @@ static void __init serial8250_isa_init_ports(void)

	if (IS_ENABLED(CONFIG_ALPHA_JENSEN) ||
	    (IS_ENABLED(CONFIG_ALPHA_GENERIC) && alpha_jensen()))
			port->set_mctrl = alpha_jensen_set_mctrl;
		up->port.set_mctrl = alpha_jensen_set_mctrl;

	serial8250_set_defaults(up);

	return up;
}

static void __init serial8250_isa_init_ports(void)
{
	struct uart_8250_port *up;
	static int first = 1;
	int i, irqflag = 0;

	if (!first)
		return;
	first = 0;

	if (nr_uarts > UART_NR)
		nr_uarts = UART_NR;

	/*
	 * Set up initial isa ports based on nr_uart module param, or else
	 * default to CONFIG_SERIAL_8250_RUNTIME_UARTS. Note that we do not
	 * need to increase nr_uarts when setting up the initial isa ports.
	 */
	for (i = 0; i < nr_uarts; i++)
		serial8250_setup_port(i);

	/* chain base port ops to support Remote Supervisor Adapter */
	univ8250_port_ops = *base_ops;
	univ8250_rsa_support(&univ8250_port_ops);
@@ -586,16 +601,29 @@ static void univ8250_console_write(struct console *co, const char *s,

static int univ8250_console_setup(struct console *co, char *options)
{
	struct uart_8250_port *up;
	struct uart_port *port;
	int retval;
	int retval, i;

	/*
	 * Check whether an invalid uart number has been specified, and
	 * if so, search for the first available port that does have
	 * console support.
	 */
	if (co->index >= nr_uarts)
	if (co->index >= UART_NR)
		co->index = 0;

	/*
	 * If the console is past the initial isa ports, init more ports up to
	 * co->index as needed and increment nr_uarts accordingly.
	 */
	for (i = nr_uarts; i <= co->index; i++) {
		up = serial8250_setup_port(i);
		if (!up)
			return -ENODEV;
		nr_uarts++;
	}

	port = &serial8250_ports[co->index].port;
	/* link port to console */
	port->cons = co;
@@ -990,7 +1018,18 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
	mutex_lock(&serial_mutex);

	uart = serial8250_find_match_or_unused(&up->port);
	if (uart && uart->port.type != PORT_8250_CIR) {
	if (!uart) {
		/*
		 * If the port is past the initial isa ports, initialize a new
		 * port and increment nr_uarts accordingly.
		 */
		uart = serial8250_setup_port(nr_uarts);
		if (!uart)
			goto unlock;
		nr_uarts++;
	}

	if (uart->port.type != PORT_8250_CIR) {
		struct mctrl_gpios *gpios;

		if (uart->port.dev)
@@ -1120,6 +1159,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
		}
	}

unlock:
	mutex_unlock(&serial_mutex);

	return ret;