Way for platforms to alter built-in serial ports
RFC PATCH 1/1 Way for platforms to alter built-in serial ports
Hi Russel !
I'm back with a finally useable fix for an oooooold problem, which is the way the serial table is supposed to be hard coded in asm/serial.h makes it really nasty to deal with for platforms like ppc where a given kernel can boot machines with different setups or even no built-in serial port at all.
(I currently have the 3 cases on ppc64: some normal ISA serial, some with different port/irq settings, and machines with no ports at all, all in the same kernel image).
The early_serial_setup() thing has never been practical to use, since it basically consist of "shoving" entries into the table, which is a bit ugly, requires knowledge of the table size if we want to remove all entries but N, that sort of thing, but the MAIN issue is that it's fundamentally incompatible with the driver beeing in a module.
What I propose is a way for the arch to provide it's own table along with the size of it via a function call. It's optional, based on a #ifdef defined by the arch in it's asm/serial.h. The only remaining tricky point is the fact that you used to size your static array of UART's based on the size of the table. So with my path, an arch that defines ARCH_HAS_GET_LEGACY_SERIAL_PORTS is supposed to provide both the new get_legacy_serial_ports() function, but also to define UART_NR to something sensible. I hope one day, we'll be able to convert 8250 to more dynamic allocation though.
With this patch, I fix all my problems of properly detecting built-in serial ports _and_ not munging around with non existing ports on machines with no legacy HW with a single kernel image on ppc64 (and hopefully on ppc32 too). I have the ppc64-side of the patch beeing tested on various hardware at the moment and will submit it if you accept this one.
Regards,
Ben.
drivers/serial/8250.c +23 -10
@@ -112,11 +112,18 @@#define SERIAL_PORT_DFNS #endif +#ifndef ARCH_HAS_GET_LEGACY_SERIAL_PORTS static struct old_serial_port old_serial_port[] = {SERIAL_PORT_DFNS /* defined in asm/serial.h */ }; - +static inline struct old_serial_port *get_legacy_serial_ports (unsigned int *count) +{ + *count =ARRAY_SIZE (old_serial_port); +return old_serial_port; +}#define UART_NR (ARRAY_SIZE(old_serial_port) + CONFIG_SERIAL_8250_NR_UARTS) +#endif /* ARCH_HAS_GET_LEGACY_SERIAL_PORTS */ +#ifdef CONFIG_SERIAL_8250_RSA
@@ -1839,22 +1846,28 @@ {struct uart_8250_port *up;static int first =1 ; +struct old_serial_port *old_ports; +int count;int i;if (!first)return ; first =0 ; -for (i =0 , up = serial8250_ports; i <ARRAY_SIZE (old_serial_port); + old_ports =get_legacy_serial_ports (&count); +if (old_ports ==NULL ) +return ; + +for (i =0 , up = serial8250_ports; i < count; i++, up++) { - up->port.iobase = old_serial_port[i].port; - up->port.irq =irq_canonicalize (old_serial_port[i].irq); - up->port.uartclk = old_serial_port[i].baud_base *16 ; - up->port.flags = old_serial_port[i].flags; - up->port.hub6 = old_serial_port[i].hub6; - up->port.membase = old_serial_port[i].iomem_base; - up->port.iotype = old_serial_port[i].io_type; - up->port.regshift = old_serial_port[i].iomem_reg_shift; + up->port.iobase = old_ports[i].port; + up->port.irq =irq_canonicalize (old_ports[i].irq); + up->port.uartclk = old_ports[i].baud_base *16 ; + up->port.flags = old_ports[i].flags; + up->port.hub6 = old_ports[i].hub6; + up->port.membase = old_ports[i].iomem_base; + up->port.iotype = old_ports[i].io_type; + up->port.regshift = old_ports[i].iomem_reg_shift; up->port.ops = &serial8250_pops;if (share_irqs) up->port.flags |=UPF_SHARE_IRQ ;
drivers/serial/8250.h +0 -12
@@ -21,18 +21,6 @@void serial8250_suspend_port (int line);void serial8250_resume_port (int line); -struct old_serial_port { -unsigned int uart; -unsigned int baud_base; -unsigned int port; -unsigned int irq; -unsigned int flags; -unsigned char hub6; -unsigned char io_type; -unsigned char *iomem_base; -unsigned short iomem_reg_shift; -}; -/* * This replaces serial_uart_config in include/linux/serial.h */
include/linux/serial.h +15 -0
@@ -14,6 +14,21 @@#include <asm/page.h> /* +* Definition of a legacy serial port +*/ +struct old_serial_port { +unsigned int uart; +unsigned int baud_base; +unsigned int port; +unsigned int irq; +unsigned int flags; +unsigned char hub6; +unsigned char io_type; +unsigned char *iomem_base; +unsigned short iomem_reg_shift; +}; + +/* * Counters of the input lines (CTS, DSR, RI, CD) interrupts */
drivers/serial/8250.c line 126
Quoted 13 lines · Benjamin Herrenschmidt
drivers/serial/8250.c +8
-1+#ifndef ARCH_HAS_GET_LEGACY_SERIAL_PORTS static struct old_serial_port old_serial_port[] = {SERIAL_PORT_DFNS /* defined in asm/serial.h */ }; - +static inline struct old_serial_port *get_legacy_serial_ports (unsigned int *count) +{ + *count =ARRAY_SIZE (old_serial_port); +return old_serial_port; +}#define UART_NR (ARRAY_SIZE(old_serial_port) + CONFIG_SERIAL_8250_NR_UARTS) +#endif /* ARCH_HAS_GET_LEGACY_SERIAL_PORTS */ +
What happens if 8250.c is built as a module andARCH_HAS_GET_LEGACY_SERIAL_PORTS is defined?
Quoted 14 lines
diff -urN
linux-2.5/include/linux/serial.hlinux-maple/include/linux/serial.hinclude/linux/serial.h +7
-0@@ -14,6 +14,21 @@#include <asm/page.h> /* +* Definition of a legacy serial port +*/ +struct old_serial_port { +unsigned int uart; +unsigned int baud_base; +unsigned int port; +unsigned int irq;
include/linux/serial.h line 33
Quoted 10 lines
include/linux/serial.h +8
-0+unsigned int flags; +unsigned char hub6; +unsigned char io_type; +unsigned char *iomem_base; +unsigned short iomem_reg_shift; +}; + +/* * Counters of the input lines (CTS, DSR, RI, CD) interrupts */
serial.h is used by userspace programs. We should not expose this structure to those programs. Instead, maybe creating an 8250.h header, or even moving the existing 8250.h header ?
Signature · 4 lines
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of: 2.6 PCMCIA - http://pcmcia.arm.linux.org.uk/
2.6 Serial coreQuoted 17 lines · Russell King
drivers/serial/8250.c line 126
Quoted 13 lines · Benjamin Herrenschmidt
drivers/serial/8250.c +8
-1+#ifndef ARCH_HAS_GET_LEGACY_SERIAL_PORTS static struct old_serial_port old_serial_port[] = {SERIAL_PORT_DFNS /* defined in asm/serial.h */ }; - +static inline struct old_serial_port *get_legacy_serial_ports (unsigned int *count) +{ + *count =ARRAY_SIZE (old_serial_port); +return old_serial_port; +}#define UART_NR (ARRAY_SIZE(old_serial_port) + CONFIG_SERIAL_8250_NR_UARTS) +#endif /* ARCH_HAS_GET_LEGACY_SERIAL_PORTS */ +What happens if 8250.c is built as a module and
ARCH_HAS_GET_LEGACY_SERIAL_PORTSis defined?
It well call get_legacy_serial_ports() which is hopefully exported by the arch code.
Quoted 3 lines
serial.his used by userspace programs. We should not expose this structure to those programs. Instead, maybe creating an 8250.h header, or even moving the existing 8250.h header ?
Hrm... ok. Or adding a #ifdef __KERNEL__ (sic !) :)
I'll send you a new patch later today as I had to do another fix, we tend to "force" register_console() apparently even when we have nothing to register because we set the "ops" to all ports even those who were never configured and we test "ops" to decide wether to succeed or fail in the console setup() callback.
Ben.
Quoted 3 lines · Russell King
serial.his used by userspace programs. We should not expose this structure to those programs. Instead, maybe creating an 8250.h header, or even moving the existing 8250.h header ?
Here's a new version of that patch that moves 8250.h to include/linux, moves the definition of old_serial_ports there, and also corrects the problem I told you about with serial console.
Let me know if I can send it to Andrew...
Ben.
drivers/serial/8250.c +27 -11
@@ -41,7 +41,7 @@#endif #include <linux/serial_core.h> -#include "8250.h" +#include <linux/8250.h> /* * Configuration:
@@ -112,11 +112,18 @@#define SERIAL_PORT_DFNS #endif +#ifndef ARCH_HAS_GET_LEGACY_SERIAL_PORTS static struct old_serial_port old_serial_port[] = {SERIAL_PORT_DFNS /* defined in asm/serial.h */ }; - +static inline struct old_serial_port *get_legacy_serial_ports (unsigned int *count) +{ + *count =ARRAY_SIZE (old_serial_port); +return old_serial_port; +}#define UART_NR (ARRAY_SIZE(old_serial_port) + CONFIG_SERIAL_8250_NR_UARTS) +#endif /* ARCH_HAS_DYNAMIC_LEGACY_SERIAL_PORTS */ +#ifdef CONFIG_SERIAL_8250_RSA
@@ -1839,22 +1846,28 @@ {struct uart_8250_port *up;static int first =1 ; +struct old_serial_port *old_ports; +int count;int i;if (!first)return ; first =0 ; -for (i =0 , up = serial8250_ports; i <ARRAY_SIZE (old_serial_port); + old_ports =get_legacy_serial_ports (&count); +if (old_ports ==NULL ) +return ; + +for (i =0 , up = serial8250_ports; i < count; i++, up++) { - up->port.iobase = old_serial_port[i].port; - up->port.irq =irq_canonicalize (old_serial_port[i].irq); - up->port.uartclk = old_serial_port[i].baud_base *16 ; - up->port.flags = old_serial_port[i].flags; - up->port.hub6 = old_serial_port[i].hub6; - up->port.membase = old_serial_port[i].iomem_base; - up->port.iotype = old_serial_port[i].io_type; - up->port.regshift = old_serial_port[i].iomem_reg_shift; + up->port.iobase = old_ports[i].port; + up->port.irq =irq_canonicalize (old_ports[i].irq); + up->port.uartclk = old_ports[i].baud_base *16 ; + up->port.flags = old_ports[i].flags; + up->port.hub6 = old_ports[i].hub6; + up->port.membase = old_ports[i].iomem_base; + up->port.iotype = old_ports[i].io_type; + up->port.regshift = old_ports[i].iomem_reg_shift; up->port.ops = &serial8250_pops;if (share_irqs) up->port.flags |=UPF_SHARE_IRQ ;
@@ -1870,6 +1883,9 @@for (i =0 ; i <UART_NR ; i++) {struct uart_8250_port *up = &serial8250_ports[i]; +if (!up->port.iobase) +continue ; + up->port.line = i; up->port.ops = &serial8250_pops;init_timer (&up->timer);
drivers/serial/8250.h deleted +0 -71
71 lines not on this page · raw message
drivers/serial/8250_pci.c +1 -2
@@ -25,13 +25,12 @@#include <linux/serial.h> #include <linux/serial_core.h> #include <linux/8250_pci.h> +#include <linux/8250.h> #include <asm/bitops.h> #include <asm/byteorder.h> #include <asm/io.h> -#include "8250.h" -/* * Definitions for PCI support. */
drivers/serial/8250_pnp.c +1 -2
@@ -25,13 +25,12 @@#include <linux/serial.h> #include <linux/serialP.h> #include <linux/serial_core.h> +#include <linux/8250.h> #include <asm/bitops.h> #include <asm/byteorder.h> #include <asm/serial.h> -#include "8250.h" -#define UNKNOWN_DEV 0x3000
drivers/serial/au1x00_uart.c +1 -1
@@ -40,7 +40,7 @@#endif #include <linux/serial_core.h> -#include "8250.h" +#include <linux/8250.h> /* * Debugging.
drivers/serial/serial_cs.c +1 -2
@@ -44,6 +44,7 @@#include <linux/serial.h> #include <linux/serial_core.h> #include <linux/major.h> +#include <linux/8250.h> #include <asm/io.h> #include <asm/system.h>
@@ -55,8 +56,6 @@#include <pcmcia/ds.h> #include <pcmcia/cisreg.h> -#include "8250.h" -#ifdef PCMCIA_DEBUG static int pc_debug =PCMCIA_DEBUG ;MODULE_PARM (pc_debug,"i" );
include/linux/8250.h new file +74 -0
74 lines not on this page · raw message