# HG changeset patch
# User awilliam@xxxxxxxxxxx
# Node ID cf4a70ab3f59b3199ddc58f80cc0ec9d11d5b5ea
# Parent bf396988059eee110a8e7a26bce69ff751e57067
[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@xxxxxx>
---
xen/arch/ia64/xen/pcdp.c | 142 ++++++++++++++++++++++++++++++++++++++++---
xen/arch/ia64/xen/xensetup.c | 33 ++++++---
2 files changed, 156 insertions(+), 19 deletions(-)
diff -r bf396988059e -r cf4a70ab3f59 xen/arch/ia64/xen/pcdp.c
--- a/xen/arch/ia64/xen/pcdp.c Fri Jun 23 09:46:39 2006 -0600
+++ b/xen/arch/ia64/xen/pcdp.c Fri Jun 23 10:04:12 2006 -0600
@@ -16,21 +16,142 @@
#include <linux/efi.h>
#include <linux/serial.h>
#ifdef XEN
+#include <linux/efi.h>
#include <linux/errno.h>
+#include <asm/iosapic.h>
+#include <asm/system.h>
+#include <acpi/acpi.h>
#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 bf396988059e -r cf4a70ab3f59 xen/arch/ia64/xen/xensetup.c
--- a/xen/arch/ia64/xen/xensetup.c Fri Jun 23 09:46:39 2006 -0600
+++ b/xen/arch/ia64/xen/xensetup.c Fri Jun 23 10:04:12 2006 -0600
@@ -23,6 +23,7 @@
#include <xen/string.h>
#include <asm/vmx.h>
#include <linux/efi.h>
+#include <asm/iosapic.h>
/* 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();
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|