lkml.org 
[lkml]   [2007]   [May]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: [PATCH]serial: make early_uart to use early_prarm instead of console_initcall
    On 5/20/07, Andrew Morton <akpm@linux-foundation.org> wrote:
    > hm, OK. I hope you guys have it under control ;)
    >
    >
    > With http://userweb.kernel.org/~akpm/config-vmm.txt I get
    >
    > drivers/built-in.o:(.data+0x5790): undefined reference to `serial8250_find_port_for_earlycon'
    >

    please check this one

    Bjorn,
    I can not find fixmap.h for ia64.....hope you can use ioremap instead,
    then we can create one dummy fixmap.h in include/asm-ia64

    [PATCH]serial: make early_uart to use early_prarm instead of console_initcall

    Make early_uart to use early_param, so uart console can be used earlier.
    Make it to be bootconsole with CON_BOOT flag, so can use console handover
    feature. and it will switch to corresponding normal serial console
    automatically.
    new command line will be

    earlycon=uart,io,0x3f8,9600n8
    earlycon=uart,io,0x3f8,9600n8 console=tty0
    earlycon=uart,mmio,0xff5e0000,115200n8

    it will print in very early stage
    Early serial console at I/O port 0x3f8 (options '9600n8')
    later for console it will print
    console handover: boot [uart0] -> real [ttyS0]

    Signed-off-by: <yinghai.lu@sun.com>
    diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
    index f74dfc4..2d37850 100644
    --- a/arch/i386/kernel/head.S
    +++ b/arch/i386/kernel/head.S
    @@ -168,6 +168,12 @@ page_pde_offset = (__PAGE_OFFSET >> 20);
    .section .init.text,"ax",@progbits
    #endif

    + /* Do an early initialization of the fixmap area */
    + movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
    + movl $(swapper_pg_pmd - __PAGE_OFFSET), %eax
    + addl $0x007, %eax /* 0x007 = PRESENT+RW+USER */
    + movl %eax, 4092(%edx)
    +
    #ifdef CONFIG_SMP
    ENTRY(startup_32_smp)
    cld
    @@ -507,6 +513,8 @@ ENTRY(_stext)
    .section ".bss.page_aligned","w"
    ENTRY(swapper_pg_dir)
    .fill 1024,4,0
    +ENTRY(swapper_pg_pmd)
    + .fill 1024,4,0
    ENTRY(empty_zero_page)
    .fill 4096,1,0

    diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
    index 1fab487..2da30ad 100644
    --- a/arch/x86_64/kernel/head.S
    +++ b/arch/x86_64/kernel/head.S
    @@ -73,7 +73,11 @@ startup_64:
    addq %rbp, init_level4_pgt + (511*8)(%rip)

    addq %rbp, level3_ident_pgt + 0(%rip)
    +
    addq %rbp, level3_kernel_pgt + (510*8)(%rip)
    + addq %rbp, level3_kernel_pgt + (511*8)(%rip)
    +
    + addq %rbp, level2_fixmap_pgt + (506*8)(%rip)

    /* Add an Identity mapping if I am above 1G */
    leaq _text(%rip), %rdi
    @@ -314,7 +318,16 @@ NEXT_PAGE(level3_kernel_pgt)
    .fill 510,8,0
    /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
    .quad level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
    - .fill 1,8,0
    + .quad level2_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE
    +
    +NEXT_PAGE(level2_fixmap_pgt)
    + .fill 506,8,0
    + .quad level1_fixmap_pgt - __START_KERNEL_map + _KERNPG_TABLE
    + /* 8MB reserved for vsyscalls + a 2MB hole = 4 + 1 entries */
    + .fill 5,8,0
    +
    +NEXT_PAGE(level1_fixmap_pgt)
    + .fill 512,8,0

    NEXT_PAGE(level2_ident_pgt)
    /* Since I easily can, map the first 1G.
    diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
    index c84dab0..5a91ac5 100644
    --- a/drivers/serial/8250.c
    +++ b/drivers/serial/8250.c
    @@ -2367,6 +2367,9 @@ static struct uart_ops serial8250_pops = {
    .request_port = serial8250_request_port,
    .config_port = serial8250_config_port,
    .verify_port = serial8250_verify_port,
    +#ifdef CONFIG_SERIAL_8250_CONSOLE
    + .find_port_for_earlycon = serial8250_find_port_for_earlycon,
    +#endif
    };

    static struct uart_8250_port serial8250_ports[UART_NR];
    @@ -2533,7 +2536,7 @@ static int __init serial8250_console_init(void)
    }
    console_initcall(serial8250_console_init);

    -static int __init find_port(struct uart_port *p)
    +int __init find_port_serial8250(struct uart_port *p)
    {
    int line;
    struct uart_port *port;
    @@ -2546,26 +2549,6 @@ static int __init find_port(struct uart_port *p)
    return -ENODEV;
    }

    -int __init serial8250_start_console(struct uart_port *port, char *options)
    -{
    - int line;
    -
    - line = find_port(port);
    - if (line < 0)
    - return -ENODEV;
    -
    - add_preferred_console("ttyS", line, options);
    - printk("Adding console on ttyS%d at %s 0x%lx (options '%s')\n",
    - line, port->iotype == UPIO_MEM ? "MMIO" : "I/O port",
    - port->iotype == UPIO_MEM ? (unsigned long) port->mapbase :
    - (unsigned long) port->iobase, options);
    - if (!(serial8250_console.flags & CON_ENABLED)) {
    - serial8250_console.flags &= ~CON_PRINTBUFFER;
    - register_console(&serial8250_console);
    - }
    - return line;
    -}
    -
    #define SERIAL8250_CONSOLE &serial8250_console
    #else
    #define SERIAL8250_CONSOLE NULL
    diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
    index 7e51119..0572a1c 100644
    --- a/drivers/serial/8250_early.c
    +++ b/drivers/serial/8250_early.c
    @@ -17,13 +17,9 @@
    * we locate the device directly by its MMIO or I/O port address.
    *
    * The user can specify the device directly, e.g.,
    - * console=uart,io,0x3f8,9600n8
    - * console=uart,mmio,0xff5e0000,115200n8
    - * or platform code can call early_uart_console_init() to set
    - * the early UART device.
    + * earlycon=uart,io,0x3f8,9600n8
    + * earlycon=uart,mmio,0xff5e0000,115200n8
    *
    - * After the normal serial driver starts, we try to locate the
    - * matching ttyS device and start a console there.
    */

    #include <linux/tty.h>
    @@ -32,8 +28,11 @@
    #include <linux/serial_core.h>
    #include <linux/serial_reg.h>
    #include <linux/serial.h>
    +#include <linux/serial_8250.h>
    #include <asm/io.h>
    #include <asm/serial.h>
    +#include <asm/pgtable.h>
    +#include <asm/fixmap.h>

    struct early_uart_device {
    struct uart_port port;
    @@ -42,7 +41,6 @@ struct early_uart_device {
    };

    static struct early_uart_device early_device __initdata;
    -static int early_uart_registered __initdata;

    static unsigned int __init serial_in(struct uart_port *port, int offset)
    {
    @@ -133,7 +131,6 @@ static void __init init_port(struct early_uart_device *device)
    static int __init parse_options(struct early_uart_device *device, char *options)
    {
    struct uart_port *port = &device->port;
    - int mapsize = 64;
    int mmio, length;

    if (!options)
    @@ -143,12 +140,9 @@ static int __init parse_options(struct early_uart_device *device, char *options)
    if (!strncmp(options, "mmio,", 5)) {
    port->iotype = UPIO_MEM;
    port->mapbase = simple_strtoul(options + 5, &options, 0);
    - port->membase = ioremap(port->mapbase, mapsize);
    - if (!port->membase) {
    - printk(KERN_ERR "%s: Couldn't ioremap 0x%lx\n",
    - __FUNCTION__, port->mapbase);
    - return -ENOMEM;
    - }
    + set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, port->mapbase & PAGE_MASK);
    + port->membase = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
    + port->membase += port->mapbase & ~PAGE_MASK;
    mmio = 1;
    } else if (!strncmp(options, "io,", 3)) {
    port->iotype = UPIO_PORT;
    @@ -175,6 +169,13 @@ static int __init parse_options(struct early_uart_device *device, char *options)
    return 0;
    }

    +static struct console early_uart_console __initdata = {
    + .name = "uart",
    + .write = early_uart_write,
    + .flags = CON_PRINTBUFFER,
    + .index = -1,
    +};
    +
    static int __init early_uart_setup(struct console *console, char *options)
    {
    struct early_uart_device *device = &early_device;
    @@ -190,61 +191,43 @@ static int __init early_uart_setup(struct console *console, char *options)
    return 0;
    }

    -static struct console early_uart_console __initdata = {
    - .name = "uart",
    - .write = early_uart_write,
    - .setup = early_uart_setup,
    - .flags = CON_PRINTBUFFER,
    - .index = -1,
    -};
    -
    -static int __init early_uart_console_init(void)
    -{
    - if (!early_uart_registered) {
    - register_console(&early_uart_console);
    - early_uart_registered = 1;
    - }
    - return 0;
    -}
    -console_initcall(early_uart_console_init);
    -
    -int __init early_serial_console_init(char *cmdline)
    +static int __init setup_early_serial_console(char *cmdline)
    {
    char *options;
    int err;

    - options = strstr(cmdline, "console=uart,");
    + options = strstr(cmdline, "uart,");
    if (!options)
    return -ENODEV;

    options = strchr(cmdline, ',') + 1;
    if ((err = early_uart_setup(NULL, options)) < 0)
    return err;
    - return early_uart_console_init();
    +
    + early_uart_console.flags |= CON_BOOT;
    + register_console(&early_uart_console);
    +
    + /* add one dummy entry in console_cmdline*/
    + add_preferred_console("ttyS", 255, early_device.options);
    +
    + return 0;
    }

    -static int __init early_uart_console_switch(void)
    +int serial8250_find_port_for_earlycon(void)
    {
    struct early_uart_device *device = &early_device;
    struct uart_port *port = &device->port;
    - int mmio, line;
    + int line;

    - if (!(early_uart_console.flags & CON_ENABLED))
    - return 0;
    + line = find_port_serial8250(port);

    - /* Try to start the normal driver on a matching line. */
    - mmio = (port->iotype == UPIO_MEM);
    - line = serial8250_start_console(port, device->options);
    if (line < 0)
    - printk("No ttyS device at %s 0x%lx for console\n",
    - mmio ? "MMIO" : "I/O port",
    - mmio ? port->mapbase :
    - (unsigned long) port->iobase);
    -
    - unregister_console(&early_uart_console);
    - if (mmio)
    - iounmap(port->membase);
    + return -ENODEV;
    +
    + /* update the dummy entry to what we want console type */
    + update_console_cmdline_console_index("ttyS", 255, line);

    return 0;
    }
    -late_initcall(early_uart_console_switch);
    +
    +early_param("earlycon", setup_early_serial_console);
    diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
    index 315ea99..b1de60d 100644
    --- a/drivers/serial/Kconfig
    +++ b/drivers/serial/Kconfig
    @@ -62,6 +62,12 @@ config SERIAL_8250_CONSOLE
    kernel will automatically use the first serial line, /dev/ttyS0, as
    system console.

    + you can set that using a kernel command line option such as
    + "earlycon=uart,io,0x3f8,9600n8" or
    + "earlycon=uart,mmio,0xfe000008,115200n8".
    + and it will switch to normal serial console when correponding port is
    + ready.
    +
    If unsure, say N.

    config SERIAL_8250_GSC
    diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
    index 326020f..956d435 100644
    --- a/drivers/serial/serial_core.c
    +++ b/drivers/serial/serial_core.c
    @@ -2303,8 +2303,11 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
    * It may be that the port was not available.
    */
    if (port->type != PORT_UNKNOWN &&
    - port->cons && !(port->cons->flags & CON_ENABLED))
    + port->cons && !(port->cons->flags & CON_ENABLED)) {
    + if(port->ops && port->ops->find_port_for_earlycon)
    + port->ops->find_port_for_earlycon();
    register_console(port->cons);
    + }

    /*
    * Ensure UPF_DEAD is not set.
    diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
    index 80ea052..249e753 100644
    --- a/include/asm-i386/fixmap.h
    +++ b/include/asm-i386/fixmap.h
    @@ -54,6 +54,8 @@ extern unsigned long __FIXADDR_TOP;
    enum fixed_addresses {
    FIX_HOLE,
    FIX_VDSO,
    + FIX_DBGP_BASE,
    + FIX_EARLYCON_MEM_BASE,
    #ifdef CONFIG_X86_LOCAL_APIC
    FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
    #endif
    diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h
    index e90e167..2acb9b7 100644
    --- a/include/asm-x86_64/fixmap.h
    +++ b/include/asm-x86_64/fixmap.h
    @@ -35,6 +35,8 @@ enum fixed_addresses {
    VSYSCALL_LAST_PAGE,
    VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,
    VSYSCALL_HPET,
    + FIX_DBGP_BASE,
    + FIX_EARLYCON_MEM_BASE,
    FIX_HPET_BASE,
    FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
    FIX_IO_APIC_BASE_0,
    @@ -84,7 +86,7 @@ static __always_inline unsigned long fix_to_virt(const unsigned int idx)
    if (idx >= __end_of_fixed_addresses)
    __this_fixmap_does_not_exist();

    - return __fix_to_virt(idx);
    + return __fix_to_virt(idx);
    }

    #endif
    diff --git a/include/linux/console.h b/include/linux/console.h
    index 62ef6e1..4cb7749 100644
    --- a/include/linux/console.h
    +++ b/include/linux/console.h
    @@ -107,6 +107,7 @@ struct console {
    };

    extern int add_preferred_console(char *name, int idx, char *options);
    +extern int update_console_cmdline_console_index(char *name, int idx_old, int idx_new);
    extern void register_console(struct console *);
    extern int unregister_console(struct console *);
    extern struct console *console_drivers;
    diff --git a/include/linux/serial.h b/include/linux/serial.h
    index 33fc8cb..deb7143 100644
    --- a/include/linux/serial.h
    +++ b/include/linux/serial.h
    @@ -177,11 +177,5 @@ struct serial_icounter_struct {
    #ifdef __KERNEL__
    #include <linux/compiler.h>

    -/* Allow architectures to override entries in serial8250_ports[] at run time: */
    -struct uart_port; /* forward declaration */
    -extern int early_serial_setup(struct uart_port *port);
    -extern int early_serial_console_init(char *options);
    -extern int serial8250_start_console(struct uart_port *port, char *options);
    -
    #endif /* __KERNEL__ */
    #endif /* _LINUX_SERIAL_H */
    diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
    index 71310d8..0d79fc5 100644
    --- a/include/linux/serial_8250.h
    +++ b/include/linux/serial_8250.h
    @@ -60,4 +60,7 @@ void serial8250_unregister_port(int line);
    void serial8250_suspend_port(int line);
    void serial8250_resume_port(int line);

    +extern int find_port_serial8250(struct uart_port *p);
    +extern int serial8250_find_port_for_earlycon(void);
    +
    #endif
    diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
    index a3ac4c8..b74fa4a 100644
    --- a/include/linux/serial_core.h
    +++ b/include/linux/serial_core.h
    @@ -199,6 +199,11 @@ struct uart_ops {
    void (*config_port)(struct uart_port *, int);
    int (*verify_port)(struct uart_port *, struct serial_struct *);
    int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
    +
    + /*
    + * for earlycon to console switch
    + */
    + int (*find_port_for_earlycon)(void);
    };

    #define UART_CONFIG_TYPE (1 << 0)
    diff --git a/kernel/printk.c b/kernel/printk.c
    index 0bbdeac..253c0f7 100644
    --- a/kernel/printk.c
    +++ b/kernel/printk.c
    @@ -726,6 +726,21 @@ int __init add_preferred_console(char *name, int idx, char *options)
    return 0;
    }

    +int __init update_console_cmdline_console_index(char *name, int idx_old, int idx_new)
    +{
    + int i;
    +
    + for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
    + if (strcmp(console_cmdline[i].name, name) == 0 &&
    + console_cmdline[i].index == idx_old) {
    + console_cmdline[i].index = idx_new;
    + return 0;
    + }
    +
    + return 0;
    +}
    +
    +
    #ifndef CONFIG_DISABLE_CONSOLE_SUSPEND
    /**
    * suspend_console - suspend the console subsystem
    \
     
     \ /
      Last update: 2007-05-21 08:59    [W:3.590 / U:0.844 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site