diff -urN linux/drivers/Makefile linux/drivers/Makefile --- linux/drivers/Makefile 2003-08-08 22:39:36.000000000 -0600 +++ linux/drivers/Makefile 2003-08-25 12:42:55.000000000 -0600 @@ -49,3 +49,4 @@ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ +obj-$(CONFIG_ACPI_EFI) += efi/ diff -urN linux/drivers/efi/Makefile linux/drivers/efi/Makefile --- linux/drivers/efi/Makefile 1969-12-31 17:00:00.000000000 -0700 +++ linux/drivers/efi/Makefile 2003-08-25 12:45:24.000000000 -0600 @@ -0,0 +1,6 @@ +# +# Makefile for EFI (Extensible Firmware Interface) drivers. +# + +obj-y += efi_console.o + diff -urN linux/drivers/efi/efi_console.c linux/drivers/efi/efi_console.c --- linux/drivers/efi/efi_console.c 1969-12-31 17:00:00.000000000 -0700 +++ linux/drivers/efi/efi_console.c 2003-08-25 14:07:17.000000000 -0600 @@ -0,0 +1,265 @@ +/* + * Copyright 2003 Hewlett-Packard Co + * Copyright 2003 Alex Williamson + * Copyright 2003 Khalid Aziz + * + * Locate EFI ConOut variable and check for VGA (non-UART) + */ +#include +#include + +#undef VERBOSE +#undef DEBUG + +#ifdef VERBOSE +#define VERB_PRINTK(x...) printk(x) +#else +#define VERB_PRINTK(x...) +#endif + +#ifdef DEBUG +#define DBG_PRINTK(x...) printk(x) +#else +#define DBG_PRINTK(x...) +#endif + +#ifdef VERBOSE +static void __init +efi_print_hw_path(efi_generic_dev_path_t *hdr) +{ + + if (hdr->type != EFI_DEV_TYPE_HW_PATH) + return; + + if (hdr->sub_type == EFI_DEV_SUBTYPE_PCI) { + efi_pci_dev_path_t pci_path; + + if (hdr->length < sizeof(efi_pci_dev_path_t)) + return; + + memcpy(&pci_path, hdr, sizeof(efi_pci_dev_path_t)); + + printk("%s(%d|%d)", EFI_DEV_PCI_NAME, + pci_path.device, pci_path.function); + return; + } + printk("Unknown hardware path"); +} + +static void __init +efi_print_acpi_path(efi_generic_dev_path_t *hdr) +{ + + if (hdr->type != EFI_DEV_TYPE_ACPI_PATH) + return; + + if (hdr->sub_type == EFI_DEV_SUBTYPE_ACPI) { + efi_acpi_dev_path_t acpi_path; + char hid_str[8]; + + if (hdr->length < sizeof(efi_acpi_dev_path_t)) + return; + + memcpy(&acpi_path, hdr, sizeof(efi_acpi_dev_path_t)); + + hid_str[0] = (char) ('@' + ((acpi_path.hid >> 10) & 0x1f)); + hid_str[1] = (char) ('@' + ((acpi_path.hid >> 5) & 0x1f)); + hid_str[2] = (char) ('@' + ((acpi_path.hid >> 0) & 0x1f)); + hid_str[3] = (char) ('0' + ((acpi_path.hid >> 28) & 0xf)); + hid_str[4] = (char) ('0' + ((acpi_path.hid >> 24) & 0xf)); + hid_str[5] = (char) ('0' + ((acpi_path.hid >> 20) & 0xf)); + hid_str[6] = (char) ('0' + ((acpi_path.hid >> 16) & 0xf)); + hid_str[7] = 0; + + printk("%s(%s,%x)", EFI_DEV_ACPI_NAME, hid_str, acpi_path.uid); + return; + } + printk("Unknown ACPI path"); +} + +static void __init +efi_print_msg_path(efi_generic_dev_path_t *hdr) +{ + + if (hdr->type != EFI_DEV_TYPE_MSG_PATH) + return; + + if (hdr->sub_type == EFI_DEV_SUBTYPE_UART) { + efi_uart_dev_path_t uart_path; + char parity; + + if (hdr->length < sizeof(efi_uart_dev_path_t)) + return; + + memcpy(&uart_path, hdr, sizeof(efi_uart_dev_path_t)); + + switch (uart_path.parity) { + case EFI_NO_PARITY: + parity = 'N'; + break; + case EFI_EVEN_PARITY: + parity = 'E'; + break; + case EFI_ODD_PARITY: + parity = 'O'; + break; + default: + parity = '?'; + } + + printk("%s(%ld %c%d%d)", EFI_DEV_UART_NAME, uart_path.baud, + parity, uart_path.bits, uart_path.stop_bits); + + return; + } + if (hdr->sub_type == EFI_DEV_SUBTYPE_VENMSG) { + efi_venmsg_dev_path_t venmsg_path; + + if (hdr->length < sizeof(efi_venmsg_dev_path_t)) + return; + + memcpy(&venmsg_path, hdr, sizeof(efi_venmsg_dev_path_t)); + + if (efi_guidcmp(EFI_PC_ANSI_GUID, venmsg_path.guid) == 0) + printk("(PcAnsi)"); + else if (efi_guidcmp(EFI_VT_100_GUID, venmsg_path.guid) == 0) + printk("(Vt100)"); + else if (efi_guidcmp(EFI_VT_100_PLUS_GUID, venmsg_path.guid) == 0) + printk("(Vt100+)"); + else if (efi_guidcmp(EFI_VT_UTF8_GUID, venmsg_path.guid) == 0) + printk("(VtUtf8)"); + else + printk("(VenMsg)"); + return; + } + printk("Unknown message path"); +} +#endif + +#ifdef VERBOSE +#define verb_print_separator() \ + if (first) { \ + first = 0; \ + } else { \ + printk("/"); \ + } +#endif + +int __init +efi_conout_has_vga(void) +{ + efi_status_t status; + efi_guid_t vendor_guid; + unsigned char efi_data[1024]; + efi_char16_t variable_name[128]; + unsigned char varname[sizeof(variable_name)/sizeof(efi_char16_t) + 1]; + unsigned long name_size, data_size, end_addr; + u32 attributes; + int i, found_end, found_vga, found_uart, first; + efi_generic_dev_path_t *hdr; + + DBG_PRINTK("Entering %s()\n", __FUNCTION__); + for (;;) { + name_size = sizeof(variable_name); + status = efi.get_next_variable(&name_size, variable_name, + &vendor_guid); + + if (status != EFI_SUCCESS) + break; + + /* + * Convert Unicode to normal chars (assume top bits + * are 0), ala UTF-8 + */ + for (i = 0; i < (name_size/sizeof(efi_char16_t)); i++) + varname[i] = variable_name[i] & 0xFF; + + varname[i] = 0; + + DBG_PRINTK("Found EFI variable %s\n", varname); + + if (strcmp(varname, "ConOut") != 0) + continue; + + data_size = sizeof(efi_data); + status = efi.get_variable(variable_name, &vendor_guid, + &attributes, &data_size, efi_data); + + if (status != EFI_SUCCESS) + continue; + + end_addr = (unsigned long)efi_data + data_size; + +#ifdef DEBUG + for (i = 0 ; i < data_size ;) { + printk("%02x", efi_data[i++]); + + if (!(i % 2)) + printk(" "); + if (!(i % 16)) + printk("\n"); + } + printk("\n"); +#endif + hdr = (efi_generic_dev_path_t *)&efi_data; + found_end = found_vga = found_uart = 0; + first = 1; + + VERB_PRINTK("EFI ConOut variable data:\n"); + + do { + switch (hdr->type) { + case EFI_DEV_TYPE_HW_PATH: +#ifdef VERBOSE + verb_print_separator(); + efi_print_hw_path(hdr); +#endif + break; + + case EFI_DEV_TYPE_ACPI_PATH: +#ifdef VERBOSE + verb_print_separator(); + efi_print_acpi_path(hdr); +#endif + break; + + case EFI_DEV_TYPE_MSG_PATH: +#ifdef VERBOSE + verb_print_separator(); + efi_print_msg_path(hdr); +#endif + if (hdr->sub_type == EFI_DEV_SUBTYPE_UART) + found_uart = 1; + break; + + case EFI_DEV_TYPE_END_PATH: + case EFI_DEV_TYPE_END_PATH2: + + if (!found_uart) { + found_vga = 1; + VERB_PRINTK(" <-- VGA"); + } + + VERB_PRINTK("\n"); + found_uart = 0; + first = 1; + + if (hdr->sub_type == EFI_DEV_SUBTYPE_END) + found_end = 1; + break; + default: + break; + } + + hdr = (efi_generic_dev_path_t *)((u8*)hdr + hdr->length); + + } while (!found_end && (unsigned long)hdr < end_addr); + + if (found_vga) { + DBG_PRINTK("Found VGA in ConOut\n"); + return 1; + } + } + DBG_PRINTK("Leaving %s()\n", __FUNCTION__); + return 0; +} diff -urN linux/drivers/serial/8250_hcdp.c linux/drivers/serial/8250_hcdp.c --- linux/drivers/serial/8250_hcdp.c 2003-08-08 22:40:06.000000000 -0600 +++ linux/drivers/serial/8250_hcdp.c 2003-08-25 13:28:17.000000000 -0600 @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -28,6 +30,158 @@ #undef SERIAL_DEBUG_HCDP +static unsigned char __initdata hcdp_fake_cmdline[32]; + +static int __init +obsolete_setup(char *param, char *val) +{ + struct obs_kernel_param *p; + extern struct obs_kernel_param __setup_start, __setup_end; + + if (val) + val[-1] = '='; + + p = &__setup_start; + do { + int n = strlen(p->str); + if (!strncmp(param,p->str,n)) { + if (p->setup_func(param+n)) + return 0; + } + p++; + } while (p < &__setup_end); + + return 0; +} + +static void __init +early_print_uart_raw(char *str, int len, unsigned long iobase) +{ + void *mmio_base; + char c; + + if (!iobase) + return; + + mmio_base = ioremap(iobase, 64UL); + + if (!mmio_base) + return; + + while (len-- > 0) { + c = *str++; + while ((readb(mmio_base + UART_LSR) & UART_LSR_TEMT) == 0) + cpu_relax(); /* spin */ + + writeb(c, mmio_base + UART_TX); + + if (c == '\n') + writeb('\r', mmio_base + UART_TX); + } +} + +#define VGABASE 0xb8000UL +#define VGALINES 24 +#define VGACOLS 80 + +static void __init +early_print_vga_raw(char *str, int len) +{ + int current_ypos = VGALINES, current_xpos = 0; + char c; + int i, k, j; + void *vgabase = ioremap(VGABASE, 4000); + + while (len-- > 0) { + c = *str++; + if (current_ypos >= VGALINES) { + /* scroll 1 line up */ + for (k = 1, j = 0; k < VGALINES; k++, j++) { + for (i = 0; i < VGACOLS; i++) { + writew(readw(vgabase + 2*(VGACOLS*k + i)), vgabase + 2*(VGACOLS*j + i)); + } + } + for (i = 0; i < VGACOLS; i++) { + writew(0x720, vgabase + 2*(VGACOLS*j + i)); + } + current_ypos = VGALINES-1; + } + if (c == '\n') { + current_xpos = 0; + current_ypos++; + } else if (c != '\r') { + writew(((0x7 << 8) | (unsigned short) c), + vgabase + 2*(VGACOLS*current_ypos + current_xpos++)); + if (current_xpos >= VGACOLS) { + current_xpos = 0; + current_ypos++; + } + } + } +} + +static void __init +setup_console_cmdline(hcdp_dev_t *hcdp) +{ + int has_vga = 0; + int has_ttyS_cmdline = 0; + int has_tty_cmdline = 0; + extern char saved_command_line[]; + char *cp; + + has_vga = efi_conout_has_vga(); + + for (cp = saved_command_line; *cp; ) { + if (memcmp(cp, "console=ttyS", 12) == 0) + has_ttyS_cmdline = 1; + else if (memcmp(cp, "console=tty", 11) == 0) + has_tty_cmdline = 1; + + while (*cp && *cp != ' ') + ++cp; + while (*cp && *cp == ' ') + ++cp; + } + + if (!has_vga && !(has_ttyS_cmdline | has_tty_cmdline)) { + extern struct kernel_param __start___param[], __stop___param[]; + + sprintf(hcdp_fake_cmdline, " console=ttyS0,%ld%c%d", + hcdp->baud, ((hcdp->parity == 0x01) ? + 'n': ((hcdp->parity == 0x02) ? 'e': + ((hcdp->parity == 0x03) ? 'o':'n'))), + hcdp->bits); + + /* + * Append a "console=..." string to + * saved_command_line so /proc/cmdline would + * show the serial console in use. + */ + strcat(saved_command_line, hcdp_fake_cmdline); + + parse_args("HCDP Console setup", hcdp_fake_cmdline, + __start___param, __stop___param - + __start___param, &obsolete_setup); + + } else if (has_vga && !has_ttyS_cmdline) { + + if (hcdp->base_addr.space_id == ACPI_MEM_SPACE) { + unsigned long iobase; + + iobase = ((u64) hcdp->base_addr.addrhi << 32) | + hcdp->base_addr.addrlo; + + early_print_uart_raw("Console initialized on VGA\n", + 27, iobase); + } + + } else if (has_vga && has_ttyS_cmdline && !has_tty_cmdline) { + + if (efi_mem_type(VGABASE) == EFI_MEMORY_MAPPED_IO) + early_print_vga_raw("Console initialized on serial\n", 30); + } +} + /* * Parse the HCDP table to find descriptions for headless console and debug * serial ports and add them to rs_table[]. A pointer to HCDP table is @@ -199,6 +353,9 @@ "Will try any additional consoles in HCDP.\n"); continue; } + + setup_console_cmdline(hcdp_dev); + break; } diff -urN linux/drivers/serial/Kconfig linux/drivers/serial/Kconfig --- linux/drivers/serial/Kconfig 2003-08-08 22:41:26.000000000 -0600 +++ linux/drivers/serial/Kconfig 2003-08-25 12:47:58.000000000 -0600 @@ -86,7 +86,7 @@ config SERIAL_8250_HCDP bool "8250/16550 device discovery support via EFI HCDP table" - depends on IA64 && SERIAL_8250 + depends on IA64 && SERIAL_8250 && ACPI_EFI ---help--- If you wish to make the serial console port described by the EFI HCDP table available for use as serial console or general diff -urN linux/include/linux/efi.h linux/include/linux/efi.h --- linux/include/linux/efi.h 2003-08-08 22:41:36.000000000 -0600 +++ linux/include/linux/efi.h 2003-08-25 12:36:48.000000000 -0600 @@ -154,6 +154,63 @@ unsigned long reset_system; } efi_runtime_services_t; +#define EFI_DEV_TYPE_HW_PATH 0x01 + #define EFI_DEV_SUBTYPE_PCI 0x1 + #define EFI_DEV_PCI_NAME "Pci" + +#define EFI_DEV_TYPE_ACPI_PATH 0x02 + #define EFI_DEV_SUBTYPE_ACPI 0x1 + #define EFI_DEV_ACPI_NAME "Acpi" + +#define EFI_DEV_TYPE_MSG_PATH 0x03 + #define EFI_DEV_SUBTYPE_UART 0x0E + #define EFI_DEV_UART_NAME "Uart" + + #define EFI_NO_PARITY 0x01 + #define EFI_EVEN_PARITY 0x02 + #define EFI_ODD_PARITY 0x03 + + #define EFI_ONE_STOP_BIT 0x01 + + #define EFI_DEV_SUBTYPE_VENMSG 0x0A + +#define EFI_DEV_TYPE_END_PATH 0xFF +#define EFI_DEV_TYPE_END_PATH2 0x7F + #define EFI_DEV_SUBTYPE_END 0xFF + #define EFI_DEV_SUBTYPE_START_NEW 0x01 + +typedef struct { + u8 type; + u8 sub_type; + u16 length; +} efi_generic_dev_path_t; + +typedef struct { + efi_generic_dev_path_t hdr; + u8 function; + u8 device; +} efi_pci_dev_path_t; + +typedef struct { + efi_generic_dev_path_t hdr; + u32 hid; + u32 uid; +} efi_acpi_dev_path_t; + +typedef struct { + efi_generic_dev_path_t hdr; + u32 reserved; + u64 baud; + u8 bits; + u8 parity; + u8 stop_bits; +} efi_uart_dev_path_t; + +typedef struct { + efi_generic_dev_path_t hdr; + efi_guid_t guid; +} efi_venmsg_dev_path_t; + typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc); typedef efi_status_t efi_set_time_t (efi_time_t *tm); typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending, @@ -194,6 +251,18 @@ #define HCDP_TABLE_GUID \ EFI_GUID( 0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 ) +#define EFI_PC_ANSI_GUID \ + EFI_GUID( 0xe0c14753, 0xf9be, 0x11d2, 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) + +#define EFI_VT_100_GUID \ + EFI_GUID( 0xdfa66065, 0xb419, 0x11d3, 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) + +#define EFI_VT_100_PLUS_GUID \ + EFI_GUID( 0x7baec70b, 0x57e0, 0x4c76, 0x8e, 0x87, 0x2f, 0x9e, 0x28, 0x08, 0x83, 0x43 ) + +#define EFI_VT_UTF8_GUID \ + EFI_GUID( 0xad15a0d6, 0x8bec, 0x4acf, 0xa0, 0x73, 0xd0, 0x1d, 0xe7, 0x7e, 0x2d, 0x88 ) + typedef struct { efi_guid_t guid; unsigned long table; @@ -266,6 +335,7 @@ extern u64 efi_get_iobase (void); extern u32 efi_mem_type (unsigned long phys_addr); extern u64 efi_mem_attributes (unsigned long phys_addr); +extern int efi_conout_has_vga(void); /* * Variable Attributes