direct-io.hg

changeset 10607:cf4a70ab3f59

[IA64] enable xencons irq for pcdp described uarts

This patch enables interrupts for xencons on UARTs described via the
HCDP/PCDP tables. This gets a little messy because the old HCDP
doesn't provide interrupt polarity/trigger info. If the UART is on a
PCI device we can assume it's low/level, otherwise we have to resort to
more creative methods. Since this old table is being phased out in
favor of the new version that does provide all the interrupt info, we
should have a fixed number of boxes out there that we have to detect (or
leave in polling mode). I've added a function to detect and setup the
HP models based on the model string found in the ACPI XSDT OEM table ID.
I also added a xencons_poll boot option in case detection goes wrong or
the table provides the wrong info, we can force it to a working state.
Removed all of the "About to call..." printks in xensetup while I was
there.

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
author awilliam@xenbuild.aw
date Fri Jun 23 10:04:12 2006 -0600 (2006-06-23)
parents bf396988059e
children d107bfd5a4ae
files xen/arch/ia64/xen/pcdp.c xen/arch/ia64/xen/xensetup.c
line diff
     1.1 --- a/xen/arch/ia64/xen/pcdp.c	Fri Jun 23 09:46:39 2006 -0600
     1.2 +++ b/xen/arch/ia64/xen/pcdp.c	Fri Jun 23 10:04:12 2006 -0600
     1.3 @@ -16,21 +16,142 @@
     1.4  #include <linux/efi.h>
     1.5  #include <linux/serial.h>
     1.6  #ifdef XEN
     1.7 +#include <linux/efi.h>
     1.8  #include <linux/errno.h>
     1.9 +#include <asm/iosapic.h>
    1.10 +#include <asm/system.h>
    1.11 +#include <acpi/acpi.h>
    1.12  #endif
    1.13  #include "pcdp.h"
    1.14  
    1.15 -static int __init
    1.16 -setup_serial_console(struct pcdp_uart *uart)
    1.17 +#ifdef XEN
    1.18 +extern struct ns16550_defaults ns16550_com1;
    1.19 +extern unsigned int ns16550_com1_gsi;
    1.20 +extern unsigned int ns16550_com1_polarity;
    1.21 +extern unsigned int ns16550_com1_trigger;
    1.22 +
    1.23 +/*
    1.24 + * This is kind of ugly, but older rev HCDP tables don't provide interrupt
    1.25 + * polarity and trigger information.  Linux/ia64 discovers these properties
    1.26 + * later via ACPI names, but we don't have that luxury in Xen/ia64.  Since
    1.27 + * all future platforms should have newer PCDP tables, this should be a
    1.28 + * fixed list of boxes in the field, so we can hardcode based on the model.
    1.29 + */
    1.30 +static void __init
    1.31 +pcdp_hp_irq_fixup(struct pcdp *pcdp, struct pcdp_uart *uart)
    1.32  {
    1.33 -#ifdef XEN
    1.34 -	extern struct ns16550_defaults ns16550_com1;
    1.35 +	efi_system_table_t *systab;
    1.36 +	efi_config_table_t *tables;
    1.37 +	struct acpi20_table_rsdp *rsdp = NULL;
    1.38 +	struct acpi_table_xsdt *xsdt;
    1.39 +	struct acpi_table_header *hdr;
    1.40 +	int i;
    1.41 +
    1.42 +	if (pcdp->rev >= 3 || strcmp(pcdp->oemid, "HP"))
    1.43 +		return;
    1.44 +
    1.45 +	/*
    1.46 +	 * Manually walk firmware provided tables to get to the XSDT.
    1.47 +	 * The OEM table ID on the XSDT is the platform model string.
    1.48 +	 * We only care about ACPI 2.0 tables as that's all HP provides.
    1.49 +	 */
    1.50 +	systab = __va(ia64_boot_param->efi_systab);
    1.51 +
    1.52 +	if (!systab || systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
    1.53 +		return;
    1.54 +
    1.55 +	tables = __va(systab->tables);
    1.56 +
    1.57 +	for (i = 0 ; i < (int)systab->nr_tables && !rsdp ; i++) {
    1.58 +		if (efi_guidcmp(tables[i].guid, ACPI_20_TABLE_GUID) == 0)
    1.59 +			rsdp =
    1.60 +			     (struct acpi20_table_rsdp *)__va(tables[i].table);
    1.61 +	}
    1.62 +
    1.63 +	if (!rsdp || strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1))
    1.64 +		return;
    1.65 +
    1.66 +	xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_address);
    1.67 +	hdr = &xsdt->header;
    1.68 +
    1.69 +	if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1))
    1.70 +		return;
    1.71 +
    1.72 +	/* Sanity check; are we still looking at HP firmware tables? */
    1.73 +	if (strcmp(hdr->oem_id, "HP"))
    1.74 +		return;
    1.75 +
    1.76 +	if (!strcmp(hdr->oem_table_id, "zx2000") ||
    1.77 +	    !strcmp(hdr->oem_table_id, "zx6000") ||
    1.78 +	    !strcmp(hdr->oem_table_id, "rx2600") ||
    1.79 +	    !strcmp(hdr->oem_table_id, "cx2600")) {
    1.80 +
    1.81 +		ns16550_com1.irq = ns16550_com1_gsi = uart->gsi;
    1.82 +		ns16550_com1_polarity = IOSAPIC_POL_HIGH;
    1.83 +		ns16550_com1_trigger = IOSAPIC_EDGE;
    1.84 +
    1.85 +	} else if (!strcmp(hdr->oem_table_id, "rx2620") ||
    1.86 +	           !strcmp(hdr->oem_table_id, "cx2620") ||
    1.87 +	           !strcmp(hdr->oem_table_id, "rx1600") ||
    1.88 +	           !strcmp(hdr->oem_table_id, "rx1620")) {
    1.89 +
    1.90 +		ns16550_com1.irq = ns16550_com1_gsi = uart->gsi;
    1.91 +		ns16550_com1_polarity = IOSAPIC_POL_LOW;
    1.92 +		ns16550_com1_trigger = IOSAPIC_LEVEL;
    1.93 +	}
    1.94 +}
    1.95 +
    1.96 +static void __init
    1.97 +setup_pcdp_irq(struct pcdp *pcdp, struct pcdp_uart *uart)
    1.98 +{
    1.99 +	/* PCDP provides full interrupt info */
   1.100 +	if (pcdp->rev >= 3) {
   1.101 +		if (uart->flags & PCDP_UART_IRQ) {
   1.102 +			ns16550_com1.irq = ns16550_com1_gsi = uart->gsi,
   1.103 +			ns16550_com1_polarity =
   1.104 +			               uart->flags & PCDP_UART_ACTIVE_LOW ?
   1.105 +		                       IOSAPIC_POL_LOW : IOSAPIC_POL_HIGH;
   1.106 +			ns16550_com1_trigger =
   1.107 +			               uart->flags & PCDP_UART_EDGE_SENSITIVE ?
   1.108 +		                       IOSAPIC_EDGE : IOSAPIC_LEVEL;
   1.109 +		}
   1.110 +		return;
   1.111 +	}
   1.112 +
   1.113 +	/* HCDP support */
   1.114 +	if (uart->pci_func & PCDP_UART_IRQ) {
   1.115 +		/*
   1.116 +		 * HCDP tables don't provide interrupt polarity/trigger
   1.117 +		 * info.  If the UART is a PCI device, we know to program
   1.118 +		 * it as low/level.  Otherwise rely on platform hacks or
   1.119 +		 * default to polling (irq = 0).
   1.120 +		 */
   1.121 +		if (uart->pci_func & PCDP_UART_PCI) {
   1.122 +			ns16550_com1.irq = ns16550_com1_gsi = uart->gsi;
   1.123 +			ns16550_com1_polarity = IOSAPIC_POL_LOW;
   1.124 +			ns16550_com1_trigger = IOSAPIC_LEVEL;
   1.125 +		} else if (!strcmp(pcdp->oemid, "HP"))
   1.126 +			pcdp_hp_irq_fixup(pcdp, uart);
   1.127 +	}
   1.128 +}
   1.129 +
   1.130 +static int __init
   1.131 +setup_serial_console(struct pcdp *pcdp, struct pcdp_uart *uart)
   1.132 +{
   1.133 +
   1.134  	ns16550_com1.baud = uart->baud;
   1.135  	ns16550_com1.io_base = uart->addr.address;
   1.136  	if (uart->bits)
   1.137  		ns16550_com1.data_bits = uart->bits;
   1.138 +
   1.139 +	setup_pcdp_irq(pcdp, uart);
   1.140 +
   1.141  	return 0;
   1.142 +}
   1.143  #else
   1.144 +static int __init
   1.145 +setup_serial_console(struct pcdp_uart *uart)
   1.146 +{
   1.147  #ifdef CONFIG_SERIAL_8250_CONSOLE
   1.148  	int mmio;
   1.149  	static char options[64];
   1.150 @@ -44,10 +165,8 @@ setup_serial_console(struct pcdp_uart *u
   1.151  #else
   1.152  	return -ENODEV;
   1.153  #endif
   1.154 -#endif
   1.155  }
   1.156  
   1.157 -#ifndef XEN
   1.158  static int __init
   1.159  setup_vga_console(struct pcdp_vga *vga)
   1.160  {
   1.161 @@ -100,7 +219,12 @@ efi_setup_pcdp_console(char *cmdline)
   1.162  	for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
   1.163  		if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) {
   1.164  			if (uart->type == PCDP_CONSOLE_UART) {
   1.165 +#ifndef XEN
   1.166  				return setup_serial_console(uart);
   1.167 +#else
   1.168 +				return setup_serial_console(pcdp, uart);
   1.169 +#endif
   1.170 +				
   1.171  			}
   1.172  		}
   1.173  	}
     2.1 --- a/xen/arch/ia64/xen/xensetup.c	Fri Jun 23 09:46:39 2006 -0600
     2.2 +++ b/xen/arch/ia64/xen/xensetup.c	Fri Jun 23 10:04:12 2006 -0600
     2.3 @@ -23,6 +23,7 @@
     2.4  #include <xen/string.h>
     2.5  #include <asm/vmx.h>
     2.6  #include <linux/efi.h>
     2.7 +#include <asm/iosapic.h>
     2.8  
     2.9  /* Be sure the struct shared_info fits on a page because it is mapped in
    2.10     domain. */
    2.11 @@ -67,6 +68,10 @@ integer_param("maxcpus", max_cpus);
    2.12  static int opt_xencons = 0;
    2.13  boolean_param("xencons", opt_xencons);
    2.14  
    2.15 +/* Toggle to allow non-legacy xencons UARTs to run in polling mode */
    2.16 +static int opt_xencons_poll = 0;
    2.17 +boolean_param("xencons_poll", opt_xencons_poll);
    2.18 +
    2.19  /*
    2.20   * opt_xenheap_megabytes: Size of Xen heap in megabytes, including:
    2.21   *	xen image
    2.22 @@ -149,6 +154,10 @@ struct ns16550_defaults ns16550_com1 = {
    2.23      .stop_bits = 1
    2.24  };
    2.25  
    2.26 +unsigned int ns16550_com1_gsi;
    2.27 +unsigned int ns16550_com1_polarity;
    2.28 +unsigned int ns16550_com1_trigger;
    2.29 +
    2.30  struct ns16550_defaults ns16550_com2 = {
    2.31      .baud      = BAUD_AUTO,
    2.32      .data_bits = 8,
    2.33 @@ -414,7 +423,6 @@ void start_kernel(void)
    2.34  	(xenheap_phys_end-__pa(heap_start)) >> 20,
    2.35  	(xenheap_phys_end-__pa(heap_start)) >> 10);
    2.36  
    2.37 -printk("About to call scheduler_init()\n");
    2.38      scheduler_init();
    2.39      idle_vcpu[0] = (struct vcpu*) ia64_r13;
    2.40      idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
    2.41 @@ -471,7 +479,6 @@ printk("num_online_cpus=%d, max_cpus=%d\
    2.42      initialise_gdb(); /* could be moved earlier */
    2.43  
    2.44      do_initcalls();
    2.45 -printk("About to call sort_main_extable()\n");
    2.46      sort_main_extable();
    2.47  
    2.48      init_rid_allocator ();
    2.49 @@ -479,12 +486,23 @@ printk("About to call sort_main_extable(
    2.50      local_irq_enable();
    2.51  
    2.52      if (opt_xencons) {
    2.53 -	    initialize_keytable();
    2.54 -	    serial_init_postirq();
    2.55 +        initialize_keytable();
    2.56 +        if (ns16550_com1_gsi) {
    2.57 +            if (opt_xencons_poll ||
    2.58 +                iosapic_register_intr(ns16550_com1_gsi,
    2.59 +                                      ns16550_com1_polarity,
    2.60 +                                      ns16550_com1_trigger) < 0) {
    2.61 +                ns16550_com1.irq = 0;
    2.62 +                ns16550_init(0, &ns16550_com1);
    2.63 +            }
    2.64 +        }
    2.65 +        serial_init_postirq();
    2.66 +
    2.67 +        /* Hide the HCDP table from dom0 */
    2.68 +        efi.hcdp = NULL;
    2.69      }
    2.70  
    2.71      /* Create initial domain 0. */
    2.72 -printk("About to call domain_create()\n");
    2.73      dom0 = domain_create(0, 0);
    2.74  
    2.75      if ( dom0 == NULL )
    2.76 @@ -496,7 +514,6 @@ printk("About to call domain_create()\n"
    2.77       * We're going to setup domain0 using the module(s) that we stashed safely
    2.78       * above our heap. The second module, if present, is an initrd ramdisk.
    2.79       */
    2.80 -    printk("About to call construct_dom0()\n");
    2.81      dom0_memory_start = (unsigned long) __va(ia64_boot_param->domain_start);
    2.82      dom0_memory_size = ia64_boot_param->domain_size;
    2.83      dom0_initrd_start = (unsigned long) __va(ia64_boot_param->initrd_start);
    2.84 @@ -513,7 +530,6 @@ printk("About to call domain_create()\n"
    2.85      if (!running_on_sim)  // slow on ski and pages are pre-initialized to zero
    2.86  	scrub_heap_pages();
    2.87  
    2.88 -printk("About to call init_trace_bufs()\n");
    2.89      init_trace_bufs();
    2.90  
    2.91      /* Give up the VGA console if DOM0 is configured to grab it. */
    2.92 @@ -522,13 +538,10 @@ printk("About to call init_trace_bufs()\
    2.93  
    2.94      domain0_ready = 1;
    2.95  
    2.96 -    printf("About to call schedulers_start dom0=%p, idle_dom=%p\n",
    2.97 -	   dom0, idle_domain);
    2.98      schedulers_start();
    2.99  
   2.100      domain_unpause_by_systemcontroller(dom0);
   2.101  
   2.102 -printk("About to call startup_cpu_idle_loop()\n");
   2.103      startup_cpu_idle_loop();
   2.104  }
   2.105