diff -r 0e5635d68de3 xen/arch/ia64/xen/pcdp.c --- a/xen/arch/ia64/xen/pcdp.c Wed Jun 21 11:17:08 2006 -0600 +++ b/xen/arch/ia64/xen/pcdp.c Thu Jun 22 10:22:11 2006 -0600 @@ -16,21 +16,142 @@ #include #include #ifdef XEN +#include #include +#include +#include +#include #endif #include "pcdp.h" -static int __init -setup_serial_console(struct pcdp_uart *uart) -{ #ifdef XEN - extern struct ns16550_defaults ns16550_com1; +extern struct ns16550_defaults ns16550_com1; +extern unsigned int ns16550_com1_gsi; +extern unsigned int ns16550_com1_polarity; +extern unsigned int ns16550_com1_trigger; + +/* + * This is kind of ugly, but older rev HCDP tables don't provide interrupt + * polarity and trigger information. Linux/ia64 discovers these properties + * later via ACPI names, but we don't have that luxury in Xen/ia64. Since + * all future platforms should have newer PCDP tables, this should be a + * fixed list of boxes in the field, so we can hardcode based on the model. + */ +static void __init +pcdp_hp_irq_fixup(struct pcdp *pcdp, struct pcdp_uart *uart) +{ + efi_system_table_t *systab; + efi_config_table_t *tables; + struct acpi20_table_rsdp *rsdp = NULL; + struct acpi_table_xsdt *xsdt; + struct acpi_table_header *hdr; + int i; + + if (pcdp->rev >= 3 || strcmp(pcdp->oemid, "HP")) + return; + + /* + * Manually walk firmware provided tables to get to the XSDT. + * The OEM table ID on the XSDT is the platform model string. + * We only care about ACPI 2.0 tables as that's all HP provides. + */ + systab = __va(ia64_boot_param->efi_systab); + + if (!systab || systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) + return; + + tables = __va(systab->tables); + + for (i = 0 ; i < (int)systab->nr_tables && !rsdp ; i++) { + if (efi_guidcmp(tables[i].guid, ACPI_20_TABLE_GUID) == 0) + rsdp = + (struct acpi20_table_rsdp *)__va(tables[i].table); + } + + if (!rsdp || strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) + return; + + xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_address); + hdr = &xsdt->header; + + if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) + return; + + /* Sanity check; are we still looking at HP firmware tables? */ + if (strcmp(hdr->oem_id, "HP")) + return; + + if (!strcmp(hdr->oem_table_id, "zx2000") || + !strcmp(hdr->oem_table_id, "zx6000") || + !strcmp(hdr->oem_table_id, "rx2600") || + !strcmp(hdr->oem_table_id, "cx2600")) { + + ns16550_com1.irq = ns16550_com1_gsi = uart->gsi; + ns16550_com1_polarity = IOSAPIC_POL_HIGH; + ns16550_com1_trigger = IOSAPIC_EDGE; + + } else if (!strcmp(hdr->oem_table_id, "rx2620") || + !strcmp(hdr->oem_table_id, "cx2620") || + !strcmp(hdr->oem_table_id, "rx1600") || + !strcmp(hdr->oem_table_id, "rx1620")) { + + ns16550_com1.irq = ns16550_com1_gsi = uart->gsi; + ns16550_com1_polarity = IOSAPIC_POL_LOW; + ns16550_com1_trigger = IOSAPIC_LEVEL; + } +} + +static void __init +setup_pcdp_irq(struct pcdp *pcdp, struct pcdp_uart *uart) +{ + /* PCDP provides full interrupt info */ + if (pcdp->rev >= 3) { + if (uart->flags & PCDP_UART_IRQ) { + ns16550_com1.irq = ns16550_com1_gsi = uart->gsi, + ns16550_com1_polarity = + uart->flags & PCDP_UART_ACTIVE_LOW ? + IOSAPIC_POL_LOW : IOSAPIC_POL_HIGH; + ns16550_com1_trigger = + uart->flags & PCDP_UART_EDGE_SENSITIVE ? + IOSAPIC_EDGE : IOSAPIC_LEVEL; + } + return; + } + + /* HCDP support */ + if (uart->pci_func & PCDP_UART_IRQ) { + /* + * HCDP tables don't provide interrupt polarity/trigger + * info. If the UART is a PCI device, we know to program + * it as low/level. Otherwise rely on platform hacks or + * default to polling (irq = 0). + */ + if (uart->pci_func & PCDP_UART_PCI) { + ns16550_com1.irq = ns16550_com1_gsi = uart->gsi; + ns16550_com1_polarity = IOSAPIC_POL_LOW; + ns16550_com1_trigger = IOSAPIC_LEVEL; + } else if (!strcmp(pcdp->oemid, "HP")) + pcdp_hp_irq_fixup(pcdp, uart); + } +} + +static int __init +setup_serial_console(struct pcdp *pcdp, struct pcdp_uart *uart) +{ + ns16550_com1.baud = uart->baud; ns16550_com1.io_base = uart->addr.address; if (uart->bits) ns16550_com1.data_bits = uart->bits; + + setup_pcdp_irq(pcdp, uart); + return 0; -#else +} +#else +static int __init +setup_serial_console(struct pcdp_uart *uart) +{ #ifdef CONFIG_SERIAL_8250_CONSOLE int mmio; static char options[64]; @@ -44,10 +165,8 @@ setup_serial_console(struct pcdp_uart *u #else return -ENODEV; #endif -#endif -} - -#ifndef XEN +} + static int __init setup_vga_console(struct pcdp_vga *vga) { @@ -100,7 +219,12 @@ efi_setup_pcdp_console(char *cmdline) for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) { if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) { if (uart->type == PCDP_CONSOLE_UART) { +#ifndef XEN return setup_serial_console(uart); +#else + return setup_serial_console(pcdp, uart); +#endif + } } } diff -r 0e5635d68de3 xen/arch/ia64/xen/xensetup.c --- a/xen/arch/ia64/xen/xensetup.c Wed Jun 21 11:17:08 2006 -0600 +++ b/xen/arch/ia64/xen/xensetup.c Thu Jun 22 10:22:11 2006 -0600 @@ -23,6 +23,7 @@ #include #include #include +#include /* Be sure the struct shared_info fits on a page because it is mapped in domain. */ @@ -66,6 +67,10 @@ integer_param("maxcpus", max_cpus); same resource). */ static int opt_xencons = 0; boolean_param("xencons", opt_xencons); + +/* Toggle to allow non-legacy xencons UARTs to run in polling mode */ +static int opt_xencons_poll = 0; +boolean_param("xencons_poll", opt_xencons_poll); /* * opt_xenheap_megabytes: Size of Xen heap in megabytes, including: @@ -148,6 +153,10 @@ struct ns16550_defaults ns16550_com1 = { .parity = 'n', .stop_bits = 1 }; + +unsigned int ns16550_com1_gsi; +unsigned int ns16550_com1_polarity; +unsigned int ns16550_com1_trigger; struct ns16550_defaults ns16550_com2 = { .baud = BAUD_AUTO, @@ -414,7 +423,6 @@ void start_kernel(void) (xenheap_phys_end-__pa(heap_start)) >> 20, (xenheap_phys_end-__pa(heap_start)) >> 10); -printk("About to call scheduler_init()\n"); scheduler_init(); idle_vcpu[0] = (struct vcpu*) ia64_r13; idle_domain = domain_create(IDLE_DOMAIN_ID, 0); @@ -471,7 +479,6 @@ printk("num_online_cpus=%d, max_cpus=%d\ initialise_gdb(); /* could be moved earlier */ do_initcalls(); -printk("About to call sort_main_extable()\n"); sort_main_extable(); init_rid_allocator (); @@ -479,12 +486,23 @@ printk("About to call sort_main_extable( local_irq_enable(); if (opt_xencons) { - initialize_keytable(); - serial_init_postirq(); + initialize_keytable(); + if (ns16550_com1_gsi) { + if (opt_xencons_poll || + iosapic_register_intr(ns16550_com1_gsi, + ns16550_com1_polarity, + ns16550_com1_trigger) < 0) { + ns16550_com1.irq = 0; + ns16550_init(0, &ns16550_com1); + } + } + serial_init_postirq(); + + /* Hide the HCDP table from dom0 */ + efi.hcdp = NULL; } /* Create initial domain 0. */ -printk("About to call domain_create()\n"); dom0 = domain_create(0, 0); if ( dom0 == NULL ) @@ -496,7 +514,6 @@ printk("About to call domain_create()\n" * We're going to setup domain0 using the module(s) that we stashed safely * above our heap. The second module, if present, is an initrd ramdisk. */ - printk("About to call construct_dom0()\n"); dom0_memory_start = (unsigned long) __va(ia64_boot_param->domain_start); dom0_memory_size = ia64_boot_param->domain_size; dom0_initrd_start = (unsigned long) __va(ia64_boot_param->initrd_start); @@ -513,7 +530,6 @@ printk("About to call domain_create()\n" if (!running_on_sim) // slow on ski and pages are pre-initialized to zero scrub_heap_pages(); -printk("About to call init_trace_bufs()\n"); init_trace_bufs(); /* Give up the VGA console if DOM0 is configured to grab it. */ @@ -522,13 +538,10 @@ printk("About to call init_trace_bufs()\ domain0_ready = 1; - printf("About to call schedulers_start dom0=%p, idle_dom=%p\n", - dom0, idle_domain); schedulers_start(); domain_unpause_by_systemcontroller(dom0); -printk("About to call startup_cpu_idle_loop()\n"); startup_cpu_idle_loop(); }