]> git.hungrycats.org Git - linux/commitdiff
acpi.c:
authorDavid Mosberger <davidm@wailua.hpl.hp.com>
Wed, 10 Apr 2002 09:44:18 +0000 (02:44 -0700)
committerDavid Mosberger <davidm@wailua.hpl.hp.com>
Wed, 10 Apr 2002 09:44:18 +0000 (02:44 -0700)
  Paul's ACPI update.

arch/ia64/kernel/acpi.c

index 501411199347b4e2018fbc60570eea4b8606378c..fca7fa836bd97c598688ad2f587c555772f632f5 100644 (file)
@@ -1,21 +1,34 @@
 /*
- * Advanced Configuration and Power Interface
+ *  acpi.c - Architecture-Specific Low-Level ACPI Support
  *
- * Based on 'ACPI Specification 1.0b' February 2, 1999 and
- * 'IA-64 Extensions to ACPI Specification' Revision 0.6
+ *  Copyright (C) 1999 VA Linux Systems
+ *  Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
+ *  Copyright (C) 2000 Hewlett-Packard Co.
+ *  Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ *  Copyright (C) 2000 Intel Corp.
+ *  Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
+ *  Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
  *
- * Copyright (C) 1999 VA Linux Systems
- * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 2000 Hewlett-Packard Co.
- * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 2000 Intel Corp.
- * Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
- *      ACPI based kernel configuration manager.
- *      ACPI 2.0 & IA64 ext 0.71
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
 #include <linux/config.h>
-
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/irq.h>
-#ifdef CONFIG_SERIAL_ACPI
-#include <linux/acpi_serial.h>
-#endif
-
-#include <asm/acpi-ext.h>
-#include <asm/acpikcfg.h>
+#include <linux/acpi.h>
 #include <asm/efi.h>
 #include <asm/io.h>
 #include <asm/iosapic.h>
 #include <asm/machvec.h>
 #include <asm/page.h>
+#include <asm/system.h>
 
-#undef ACPI_DEBUG              /* Guess what this does? */
-
-/* global array to record platform interrupt vectors for generic int routing */
-int platform_irq_list[ACPI_MAX_PLATFORM_IRQS];
 
-/* These are ugly but will be reclaimed by the kernel */
-int __initdata available_cpus;
-int __initdata total_cpus;
-
-void (*pm_idle) (void);
-void (*pm_power_off) (void);
+#define PREFIX                 "ACPI: "
 
 asm (".weak iosapic_register_irq");
 asm (".weak iosapic_register_legacy_irq");
@@ -53,10 +53,16 @@ asm (".weak iosapic_register_platform_irq");
 asm (".weak iosapic_init");
 asm (".weak iosapic_version");
 
+void (*pm_idle) (void);
+void (*pm_power_off) (void);
+
+
+/*
+ * TBD: Should go away once we have an ACPI parser.
+ */
 const char *
 acpi_get_sysname (void)
 {
-       /* the following should go away once we have an ACPI parser: */
 #ifdef CONFIG_IA64_GENERIC
        return "hpsim";
 #else
@@ -72,16 +78,19 @@ acpi_get_sysname (void)
 #      error Unknown platform.  Fix acpi.c.
 # endif
 #endif
-
 }
 
+#define ACPI_MAX_PLATFORM_IRQS 256
+
+/* Array to record platform interrupt vectors for generic interrupt routing. */
+int platform_irq_list[ACPI_MAX_PLATFORM_IRQS];
+
 /*
- * Interrupt routing API for device drivers.
- * Provides the interrupt vector for a generic platform event
- * (currently only CPEI implemented)
+ * Interrupt routing API for device drivers.  Provides interrupt vector for
+ * a generic platform event.  Currently only CPEI is implemented.
  */
 int
-acpi_request_vector(u32 int_type)
+acpi_request_vector (u32 int_type)
 {
        int vector = -1;
 
@@ -94,586 +103,492 @@ acpi_request_vector(u32 int_type)
        return vector;
 }
 
-/*
- * Configure legacy IRQ information.
- */
-static void __init
-acpi_legacy_irq (char *p)
-{
-       acpi_entry_int_override_t *legacy = (acpi_entry_int_override_t *) p;
-       unsigned long polarity = 0, edge_triggered = 0;
 
-       /*
-        * If the platform we're running doesn't define
-        * iosapic_register_legacy_irq(), we ignore this info...
-        */
-       if (!iosapic_register_legacy_irq)
-               return;
-
-       switch (legacy->flags) {
-             case 0x5: polarity = 1; edge_triggered = 1; break;
-             case 0x7: polarity = 0; edge_triggered = 1; break;
-             case 0xd: polarity = 1; edge_triggered = 0; break;
-             case 0xf: polarity = 0; edge_triggered = 0; break;
-             default:
-               printk("    ACPI Legacy IRQ 0x%02x: Unknown flags 0x%x\n", legacy->isa_irq,
-                      legacy->flags);
-               break;
-       }
-       iosapic_register_legacy_irq(legacy->isa_irq, legacy->pin, polarity, edge_triggered);
-}
+/* --------------------------------------------------------------------------
+                            Boot-time Table Parsing
+   -------------------------------------------------------------------------- */
 
-/*
- * ACPI 2.0 tables parsing functions
- */
+static int                     total_cpus __initdata;
+static int                     available_cpus __initdata;
+struct acpi_table_madt *       acpi_madt __initdata;
 
-static unsigned long
-readl_unaligned(void *p)
+
+static int __init
+acpi_parse_lapic_addr_ovr (acpi_table_entry_header *header)
 {
-       unsigned long ret;
+       struct acpi_table_lapic_addr_ovr *lapic = NULL;
+
+       lapic = (struct acpi_table_lapic_addr_ovr *) header;
+       if (!lapic)
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
 
-       memcpy(&ret, p, sizeof(long));
-       return ret;
+       if (lapic->address) {
+               iounmap((void *) ipi_base_addr);
+               ipi_base_addr = (unsigned long) ioremap(lapic->address, 0);
+       }
+
+       return 0;
 }
 
-/*
- * Identify usable CPU's and remember them for SMP bringup later.
- */
-static void __init
-acpi20_lsapic (char *p)
+
+static int __init
+acpi_parse_lsapic (acpi_table_entry_header *header)
 {
-       int add = 1;
+       struct acpi_table_lsapic *lsapic = NULL;
 
-       acpi20_entry_lsapic_t *lsapic = (acpi20_entry_lsapic_t *) p;
-       printk("      CPU %.04x:%.04x: ", lsapic->eid, lsapic->id);
+       lsapic = (struct acpi_table_lsapic *) header;
+       if (!lsapic)
+               return -EINVAL;
 
-       if ((lsapic->flags & LSAPIC_ENABLED) == 0) {
-               printk("disabled.\n");
-               add = 0;
-       }
+       acpi_table_print_madt_entry(header);
 
-#ifdef CONFIG_SMP
-       smp_boot_data.cpu_phys_id[total_cpus] = -1;
-#endif
-       if (add) {
+       printk("CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid);
+
+       if (lsapic->flags.enabled) {
                available_cpus++;
-               printk("available");
+               printk(" enabled");
 #ifdef CONFIG_SMP
                smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
                if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus])
                        printk(" (BSP)");
 #endif
-               printk(".\n");
        }
+       else {
+               printk(" disabled");
+#ifdef CONFIG_SMP
+               smp_boot_data.cpu_phys_id[total_cpus] = -1;
+#endif
+       }
+
+       printk("\n");
+
        total_cpus++;
+       return 0;
 }
 
-/*
- * Extract iosapic info from madt (again) to determine which iosapic
- * this platform interrupt resides in
- */
+
+static int __init
+acpi_parse_lapic_nmi (acpi_table_entry_header *header)
+{
+       struct acpi_table_lapic_nmi *lacpi_nmi = NULL;
+
+       lacpi_nmi = (struct acpi_table_lapic_nmi*) header;
+       if (!lacpi_nmi)
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+       /* TBD: Support lapic_nmi entries */
+
+       return 0;
+}
+
+
 static int __init
-acpi20_which_iosapic (int global_vector, acpi_madt_t *madt, u32 *irq_base, char **iosapic_address)
+acpi_find_iosapic (int global_vector, u32 *irq_base, char **iosapic_address)
 {
-       acpi_entry_iosapic_t *iosapic;
-       char *p, *end;
-       int ver, max_pin;
+       struct acpi_table_iosapic *iosapic = NULL;
+       int ver = 0;
+       int max_pin = 0;
+       char *p = 0;
+       char *end = 0;
 
-       p = (char *) (madt + 1);
-       end = p + (madt->header.length - sizeof(acpi_madt_t));
+       if (!irq_base || !iosapic_address)
+               return -ENODEV;
+
+       p = (char *) (acpi_madt + 1);
+       end = p + (acpi_madt->header.length - sizeof(struct acpi_table_madt));
 
        while (p < end) {
-               switch (*p) {
-                     case ACPI20_ENTRY_IO_SAPIC:
-                       /* collect IOSAPIC info for platform int use later */
-                       iosapic = (acpi_entry_iosapic_t *)p;
-                       *irq_base = iosapic->irq_base;
+               if (*p == ACPI_MADT_IOSAPIC) {
+                       iosapic = (struct acpi_table_iosapic *) p;
+
+                       *irq_base = iosapic->global_irq_base;
                        *iosapic_address = ioremap(iosapic->address, 0);
-                       /* is this the iosapic we're looking for? */
+
                        ver = iosapic_version(*iosapic_address);
                        max_pin = (ver >> 16) & 0xff;
+
                        if ((global_vector - *irq_base) <= max_pin)
-                               return 0;               /* found it! */
-                       break;
-                     default:
-                       break;
+                               return 0;       /* Found it! */
                }
                p += p[1];
        }
-       return 1;
+       return -ENODEV;
 }
 
-/*
- * Info on platform interrupt sources: NMI, PMI, INIT, etc.
- */
-static void __init
-acpi20_platform (char *p, acpi_madt_t *madt)
+
+static int __init
+acpi_parse_iosapic (acpi_table_entry_header *header)
 {
-       int vector;
-       u32 irq_base;
-       char *iosapic_address;
-       unsigned long polarity = 0, trigger = 0;
-       acpi20_entry_platform_src_t *plat = (acpi20_entry_platform_src_t *) p;
+       struct acpi_table_iosapic *iosapic;
 
-       printk("PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u\n",
-              plat->iosapic_vector, plat->global_vector, plat->eid, plat->id);
+       iosapic = (struct acpi_table_iosapic *) header;
+       if (!iosapic)
+               return -EINVAL;
 
-       /* record platform interrupt vectors for generic int routing code */
+       acpi_table_print_madt_entry(header);
 
-       if (!iosapic_register_platform_irq) {
-               printk("acpi20_platform(): no ACPI platform IRQ support\n");
-               return;
+       if (iosapic_init) {
+#ifndef CONFIG_ITANIUM
+               /* PCAT_COMPAT flag indicates dual-8259 setup */
+               iosapic_init(iosapic->address, iosapic->global_irq_base,
+                            acpi_madt->flags.pcat_compat);
+#else
+               /* Firmware on old Itanium systems is broken */
+               iosapic_init(iosapic->address, iosapic->global_irq_base, 1);
+#endif
        }
+       return 0;
+}
+
+
+static int __init
+acpi_parse_plat_int_src (acpi_table_entry_header *header)
+{
+       struct acpi_table_plat_int_src *plintsrc = NULL;
+       int vector = 0;
+       u32 irq_base = 0;
+       char *iosapic_address = NULL;
 
-       /* extract polarity and trigger info from flags */
-       switch (plat->flags) {
-             case 0x5: polarity = 1; trigger = 1; break;
-             case 0x7: polarity = 0; trigger = 1; break;
-             case 0xd: polarity = 1; trigger = 0; break;
-             case 0xf: polarity = 0; trigger = 0; break;
-             default:
-               printk("acpi20_platform(): unknown flags 0x%x\n", plat->flags);
-               break;
+       plintsrc = (struct acpi_table_plat_int_src *) header;
+       if (!plintsrc)
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+       if (!iosapic_register_platform_irq) {
+               printk(KERN_WARNING PREFIX "No ACPI platform IRQ support\n");
+               return -ENODEV;
        }
 
-       /* which iosapic does this IRQ belong to? */
-       if (acpi20_which_iosapic(plat->global_vector, madt, &irq_base, &iosapic_address)) {
-               printk("acpi20_platform(): I/O SAPIC not found!\n");
-               return;
+       if (0 != acpi_find_iosapic(plintsrc->global_irq, &irq_base, &iosapic_address)) {
+               printk(KERN_WARNING PREFIX "IOSAPIC not found\n");
+               return -ENODEV;
        }
 
        /*
-        * get vector assignment for this IRQ, set attributes, and program the IOSAPIC
-        * routing table
+        * Get vector assignment for this IRQ, set attributes, and program the
+        * IOSAPIC routing table.
         */
-       vector = iosapic_register_platform_irq(plat->int_type,
-                                              plat->global_vector,
-                                              plat->iosapic_vector,
-                                              plat->eid,
-                                              plat->id,
-                                              polarity,
-                                              trigger,
-                                              irq_base,
-                                              iosapic_address);
-       platform_irq_list[plat->int_type] = vector;
+       vector = iosapic_register_platform_irq (plintsrc->type,
+                                               plintsrc->global_irq,
+                                               plintsrc->iosapic_vector,
+                                               plintsrc->eid,
+                                               plintsrc->id,
+                                               (plintsrc->flags.polarity == 1) ? 1 : 0,
+                                               (plintsrc->flags.trigger == 1) ? 1 : 0,
+                                               irq_base,
+                                               iosapic_address);
+
+       platform_irq_list[plintsrc->type] = vector;
+       return 0;
 }
 
-/*
- * Override the physical address of the local APIC in the MADT stable header.
- */
-static void __init
-acpi20_lapic_addr_override (char *p)
+
+static int __init
+acpi_parse_int_src_ovr (acpi_table_entry_header *header)
 {
-       acpi20_entry_lapic_addr_override_t * lapic = (acpi20_entry_lapic_addr_override_t *) p;
+       struct acpi_table_int_src_ovr *p = NULL;
 
-       if (lapic->lapic_address) {
-               iounmap((void *)ipi_base_addr);
-               ipi_base_addr = (unsigned long) ioremap(lapic->lapic_address, 0);
+       p = (struct acpi_table_int_src_ovr *) header;
+       if (!p)
+               return -EINVAL;
 
-               printk("LOCAL ACPI override to 0x%lx(p=0x%lx)\n",
-                      ipi_base_addr, lapic->lapic_address);
-       }
+       acpi_table_print_madt_entry(header);
+
+       /* Ignore if the platform doesn't support overrides */
+       if (!iosapic_register_legacy_irq)
+               return 0;
+
+       iosapic_register_legacy_irq(p->bus_irq, p->global_irq,
+               (p->flags.polarity == 1) ? 1 : 0,
+               (p->flags.trigger == 1) ? 1 : 0);
+
+       return 0;
 }
 
-/*
- * Parse the ACPI Multiple APIC Description Table
- */
-static void __init
-acpi20_parse_madt (acpi_madt_t *madt)
+
+static int __init
+acpi_parse_nmi_src (acpi_table_entry_header *header)
 {
-       acpi_entry_iosapic_t *iosapic = NULL;
-       acpi20_entry_lsapic_t *lsapic = NULL;
-       char *p, *end;
-       int i;
-
-       /* Base address of IPI Message Block */
-       if (madt->lapic_address) {
-               ipi_base_addr = (unsigned long) ioremap(madt->lapic_address, 0);
-               printk("Lapic address set to 0x%lx\n", ipi_base_addr);
-       } else
-               printk("Lapic address set to default 0x%lx\n", ipi_base_addr);
+       struct acpi_table_nmi_src *nmi_src = NULL;
 
-       p = (char *) (madt + 1);
-       end = p + (madt->header.length - sizeof(acpi_madt_t));
+       nmi_src = (struct acpi_table_nmi_src*) header;
+       if (!nmi_src)
+               return -EINVAL;
 
-       /* Initialize platform interrupt vector array */
-       for (i = 0; i < ACPI_MAX_PLATFORM_IRQS; i++)
-               platform_irq_list[i] = -1;
+       acpi_table_print_madt_entry(header);
 
-       /*
-        * Split-up entry parsing to ensure ordering.
-        */
-       while (p < end) {
-               switch (*p) {
-                     case ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE:
-                       printk("ACPI 2.0 MADT: LOCAL APIC Override\n");
-                       acpi20_lapic_addr_override(p);
-                       break;
-
-                     case ACPI20_ENTRY_LOCAL_SAPIC:
-                       printk("ACPI 2.0 MADT: LOCAL SAPIC\n");
-                       lsapic = (acpi20_entry_lsapic_t *) p;
-                       acpi20_lsapic(p);
-                       break;
-
-                     case ACPI20_ENTRY_IO_SAPIC:
-                       iosapic = (acpi_entry_iosapic_t *) p;
-                       if (iosapic_init)
-                               /*
-                                * The PCAT_COMPAT flag indicates that the system has a
-                                * dual-8259 compatible setup.
-                                */
-                               iosapic_init(iosapic->address, iosapic->irq_base,
-#ifdef CONFIG_ITANIUM
-                                            1 /* fw on some Itanium systems is broken... */
-#else
-                                            (madt->flags & MADT_PCAT_COMPAT)
-#endif
-                                       );
-                       break;
-
-                     case ACPI20_ENTRY_PLATFORM_INT_SOURCE:
-                       printk("ACPI 2.0 MADT: PLATFORM INT SOURCE\n");
-                       acpi20_platform(p, madt);
-                       break;
-
-                     case ACPI20_ENTRY_LOCAL_APIC:
-                       printk("ACPI 2.0 MADT: LOCAL APIC entry\n"); break;
-                     case ACPI20_ENTRY_IO_APIC:
-                       printk("ACPI 2.0 MADT: IO APIC entry\n"); break;
-                     case ACPI20_ENTRY_NMI_SOURCE:
-                       printk("ACPI 2.0 MADT: NMI SOURCE entry\n"); break;
-                     case ACPI20_ENTRY_LOCAL_APIC_NMI:
-                       printk("ACPI 2.0 MADT: LOCAL APIC NMI entry\n"); break;
-                     case ACPI20_ENTRY_INT_SRC_OVERRIDE:
-                       break;
-                     default:
-                       printk("ACPI 2.0 MADT: unknown entry skip\n"); break;
-                       break;
-               }
-               p += p[1];
-       }
+       /* TBD: Support nimsrc entries */
 
-       p = (char *) (madt + 1);
-       end = p + (madt->header.length - sizeof(acpi_madt_t));
+       return 0;
+}
 
-       while (p < end) {
-               switch (*p) {
-                     case ACPI20_ENTRY_LOCAL_APIC:
-                       if (lsapic) break;
-                       printk("ACPI 2.0 MADT: LOCAL APIC entry\n");
-                       /* parse local apic if there's no local Sapic */
-                       break;
-                     case ACPI20_ENTRY_IO_APIC:
-                       if (iosapic) break;
-                       printk("ACPI 2.0 MADT: IO APIC entry\n");
-                       /* parse ioapic if there's no ioSapic */
-                       break;
-                     default:
-                       break;
-               }
-               p += p[1];
-       }
 
-       p = (char *) (madt + 1);
-       end = p + (madt->header.length - sizeof(acpi_madt_t));
+static int __init
+acpi_parse_madt (unsigned long phys_addr, unsigned long size)
+{
+       int i = 0;
 
-       while (p < end) {
-               switch (*p) {
-                     case ACPI20_ENTRY_INT_SRC_OVERRIDE:
-                       printk("ACPI 2.0 MADT: INT SOURCE Override\n");
-                       acpi_legacy_irq(p);
-                       break;
-                     default:
-                       break;
-               }
-               p += p[1];
+       if (!phys_addr || !size)
+               return -EINVAL;
+
+       acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
+       if (!acpi_madt) {
+               printk(KERN_WARNING PREFIX "Unable to map MADT\n");
+               return -ENODEV;
        }
 
-       /* Make bootup pretty */
-       printk("      %d CPUs available, %d CPUs total\n",
-               available_cpus, total_cpus);
+       /* Initialize platform interrupt vector array */
+
+       for (i = 0; i < ACPI_MAX_PLATFORM_IRQS; i++)
+               platform_irq_list[i] = -1;
+
+       /* Get base address of IPI Message Block */
+
+       if (acpi_madt->lapic_address)
+               ipi_base_addr = (unsigned long)
+                       ioremap(acpi_madt->lapic_address, 0);
+
+       printk(KERN_INFO PREFIX "Local APIC address 0x%lx\n", ipi_base_addr);
+
+       return 0;
 }
 
+
 int __init
-acpi20_parse (acpi20_rsdp_t *rsdp20)
+acpi_find_rsdp (unsigned long *rsdp_phys)
 {
-# ifdef CONFIG_ACPI
-       acpi_xsdt_t *xsdt;
-       acpi_desc_table_hdr_t *hdrp;
-       acpi_madt_t *madt;
-       int tables, i;
-
-       if (strncmp(rsdp20->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) {
-               printk("ACPI 2.0 RSDP signature incorrect!\n");
-               return 0;
-       } else {
-               printk("ACPI 2.0 Root System Description Ptr at 0x%lx\n",
-                       (unsigned long)rsdp20);
-       }
+       if (!rsdp_phys)
+               return -EINVAL;
 
-       xsdt = __va(rsdp20->xsdt);
-       hdrp = &xsdt->header;
-       if (strncmp(hdrp->signature,
-               ACPI_XSDT_SIG, ACPI_XSDT_SIG_LEN)) {
-               printk("ACPI 2.0 XSDT signature incorrect. Trying RSDT\n");
-               /* RSDT parsing here */
+       if (efi.acpi20) {
+               (*rsdp_phys) = __pa(efi.acpi20);
                return 0;
-       } else {
-               printk("ACPI 2.0 XSDT at 0x%lx (p=0x%lx)\n",
-               (unsigned long)xsdt, (unsigned long)rsdp20->xsdt);
        }
+       else if (efi.acpi) {
+               printk(KERN_WARNING PREFIX "v1.0/r0.71 tables no longer supported\n");
+       }
+
+       return -ENODEV;
+}
 
-       printk("ACPI 2.0: %.6s %.8s %d.%d\n",
-               hdrp->oem_id,
-               hdrp->oem_table_id,
-               hdrp->oem_revision >> 16,
-               hdrp->oem_revision & 0xffff);
 
-       acpi_cf_init((void *)rsdp20);
+#ifdef CONFIG_SERIAL_ACPI
 
-       tables =(hdrp->length -sizeof(acpi_desc_table_hdr_t))>>3;
+#include <linux/acpi_serial.h>
 
-       for (i = 0; i < tables; i++) {
-               hdrp = (acpi_desc_table_hdr_t *) __va(readl_unaligned(&xsdt->entry_ptrs[i]));
-               printk("        :table %4.4s found\n", hdrp->signature);
+static int __init
+acpi_parse_spcr (unsigned long phys_addr, unsigned long size)
+{
+       acpi_ser_t *spcr = NULL;
+       unsigned long global_int = 0;
 
-               /* Only interested int the MADT table for now ... */
-               if (strncmp(hdrp->signature,
-                       ACPI_MADT_SIG, ACPI_MADT_SIG_LEN) != 0)
-                       continue;
+       if (!phys_addr || !size)
+               return -EINVAL;
 
-               /* Save MADT pointer for later */
-               madt = (acpi_madt_t *) hdrp;
-               acpi20_parse_madt(madt);
-       }
+       if (!iosapic_register_irq)
+               return -ENODEV;
 
-#ifdef CONFIG_SERIAL_ACPI
        /*
-        * Now we're interested in other tables.  We want the iosapics already
-        * initialized, so we do it in a separate loop.
+        * ACPI is able to describe serial ports that live at non-standard
+        * memory addresses and use non-standard interrupts, either via
+        * direct SAPIC mappings or via PCI interrupts.  We handle interrupt
+        * routing for SAPIC-based (non-PCI) devices here.  Interrupt routing
+        * for PCI devices will be handled when processing the PCI Interrupt
+        * Routing Table (PRT).
         */
-       for (i = 0; i < tables; i++) {
-               hdrp = (acpi_desc_table_hdr_t *) __va(readl_unaligned(&xsdt->entry_ptrs[i]));
-               /*
-                * search for SPCR and DBGP table entries so we can enable
-                * non-pci interrupts to IO-SAPICs.
-                */
-               if (!strncmp(hdrp->signature, ACPI_SPCRT_SIG, ACPI_SPCRT_SIG_LEN) ||
-                   !strncmp(hdrp->signature, ACPI_DBGPT_SIG, ACPI_DBGPT_SIG_LEN))
-               {
-                       acpi_ser_t *spcr = (void *)hdrp;
-                       unsigned long global_int;
-
-                       setup_serial_acpi(hdrp);
-
-                       /*
-                        * ACPI is able to describe serial ports that live at non-standard
-                        * memory space addresses and use SAPIC interrupts.  If not also
-                        * PCI devices, there would be no interrupt vector information for
-                        * them.  This checks for and fixes that situation.
-                        */
-                       if (spcr->length < sizeof(acpi_ser_t))
-                               /* table is not long enough for full info, thus no int */
-                               break;
-
-                       /*
-                        * If the device is not in PCI space, but uses a SAPIC interrupt,
-                        * we need to program the SAPIC so that serial can autoprobe for
-                        * the IA64 interrupt vector later on.  If the device is in PCI
-                        * space, it should already be setup via the PCI vectors
-                        */
-                       if (spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE &&
-                           spcr->int_type == ACPI_SERIAL_INT_SAPIC)
-                       {
-                               u32 irq_base;
-                               char *iosapic_address;
-                               int vector;
-
-                               /* We have a UART in memory space with a SAPIC interrupt */
-                               global_int = (  (spcr->global_int[3] << 24)
-                                             | (spcr->global_int[2] << 16)
-                                             | (spcr->global_int[1] << 8)
-                                             | spcr->global_int[0]);
-
-                               if (!iosapic_register_irq)
-                                       continue;
-
-                               /* which iosapic does this IRQ belong to? */
-                               if (acpi20_which_iosapic(global_int, madt, &irq_base,
-                                                        &iosapic_address) == 0)
-                               {
-                                       vector = iosapic_register_irq(global_int,
-                                                                     1, /* active high polarity */
-                                                                     1, /* edge triggered */
-                                                                     irq_base,
-                                                                     iosapic_address);
-                               }
-                       }
-               }
+
+       spcr = (acpi_ser_t *) __va(phys_addr);
+       if (!spcr) {
+               printk(KERN_WARNING PREFIX "Unable to map SPCR\n");
+               return -ENODEV;
        }
-#endif
-       acpi_cf_terminate();
 
-#  ifdef CONFIG_SMP
-       if (available_cpus == 0) {
-               printk("ACPI: Found 0 CPUS; assuming 1\n");
-               available_cpus = 1; /* We've got at least one of these, no? */
+       setup_serial_acpi(spcr);
+
+       if (spcr->length < sizeof(acpi_ser_t))
+               /* Table not long enough for full info, thus no interrupt */
+               return -ENODEV;
+
+       if ((spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE) &&
+           (spcr->int_type == ACPI_SERIAL_INT_SAPIC))
+       {
+               u32 irq_base = 0;
+               char *iosapic_address = NULL;
+               int vector = 0;
+
+               /* We have a UART in memory space with an SAPIC interrupt */
+
+               global_int = (  (spcr->global_int[3] << 24) |
+                               (spcr->global_int[2] << 16) |
+                               (spcr->global_int[1] << 8)  |
+                               (spcr->global_int[0])  );
+
+               /* Which iosapic does this IRQ belong to? */
+
+               if (0 == acpi_find_iosapic(global_int, &irq_base, &iosapic_address)) {
+                       vector = iosapic_register_irq (global_int, 1, 1,
+                                                      irq_base, iosapic_address);
+               }
        }
-       smp_boot_data.cpu_count = total_cpus;
-#  endif
-# endif /* CONFIG_ACPI */
-       return 1;
+       return 0;
 }
-/*
- * ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all
- * platforms start supporting ACPI 2.0
- */
 
-/*
- * Identify usable CPU's and remember them for SMP bringup later.
- */
-static void __init
-acpi_lsapic (char *p)
+#endif /*CONFIG_SERIAL_ACPI*/
+
+
+int __init
+acpi_boot_init (char *cmdline)
 {
-       int add = 1;
+       int result = 0;
+
+       /* Initialize the ACPI boot-time table parser */
+       result = acpi_table_init(cmdline);
+       if (0 != result)
+               return result;
 
-       acpi_entry_lsapic_t *lsapic = (acpi_entry_lsapic_t *) p;
+       /*
+        * MADT
+        * ----
+        * Parse the Multiple APIC Description Table (MADT), if exists.
+        * Note that this table provides platform SMP configuration
+        * information -- the successor to MPS tables.
+        */
 
-       if ((lsapic->flags & LSAPIC_PRESENT) == 0)
-               return;
+       result = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
+       if (1 > result)
+               return result;
 
-       printk("      CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id);
+       /* Local APIC */
 
-       if ((lsapic->flags & LSAPIC_ENABLED) == 0) {
-               printk("Disabled.\n");
-               add = 0;
-       } else if (lsapic->flags & LSAPIC_PERFORMANCE_RESTRICTED) {
-               printk("Performance Restricted; ignoring.\n");
-               add = 0;
+       result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr);
+       if (0 > result) {
+               printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n");
+               return result;
        }
 
-#ifdef CONFIG_SMP
-       smp_boot_data.cpu_phys_id[total_cpus] = -1;
-#endif
-       if (add) {
-               printk("Available.\n");
-               available_cpus++;
-#ifdef CONFIG_SMP
-               smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
-#endif /* CONFIG_SMP */
+       result = acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic);
+       if (1 > result) {
+               printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries!\n");
+               return -ENODEV;
        }
-       total_cpus++;
-}
 
-/*
- * Info on platform interrupt sources: NMI. PMI, INIT, etc.
- */
-static void __init
-acpi_platform (char *p)
-{
-       acpi_entry_platform_src_t *plat = (acpi_entry_platform_src_t *) p;
+       result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi);
+       if (0 > result) {
+               printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
+               return result;
+       }
 
-       printk("PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u\n",
-              plat->iosapic_vector, plat->global_vector, plat->eid, plat->id);
-}
+       /* I/O APIC */
 
-/*
- * Parse the ACPI Multiple SAPIC Table
- */
-static void __init
-acpi_parse_msapic (acpi_sapic_t *msapic)
-{
-       acpi_entry_iosapic_t *iosapic;
-       char *p, *end;
+       result = acpi_table_parse_madt(ACPI_MADT_IOSAPIC, acpi_parse_iosapic);
+       if (1 > result) {
+               printk(KERN_ERR PREFIX "Error parsing MADT - no IOAPIC entries!\n");
+               return ((result == 0) ? -ENODEV : result);
+       }
 
-       /* Base address of IPI Message Block */
-       ipi_base_addr = (unsigned long) ioremap(msapic->interrupt_block, 0);
+       /* System-Level Interrupt Routing */
 
-       p = (char *) (msapic + 1);
-       end = p + (msapic->header.length - sizeof(acpi_sapic_t));
+       result = acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src);
+       if (0 > result) {
+               printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n");
+               return result;
+       }
 
-       while (p < end) {
-               switch (*p) {
-                     case ACPI_ENTRY_LOCAL_SAPIC:
-                       acpi_lsapic(p);
-                       break;
-
-                     case ACPI_ENTRY_IO_SAPIC:
-                       iosapic = (acpi_entry_iosapic_t *) p;
-                       if (iosapic_init)
-                               /*
-                                * The ACPI I/O SAPIC table doesn't have a PCAT_COMPAT
-                                * flag like the MADT table, but we can safely assume that
-                                * ACPI 1.0b systems have a dual-8259 setup.
-                                */
-                               iosapic_init(iosapic->address, iosapic->irq_base, 1);
-                       break;
-
-                     case ACPI_ENTRY_INT_SRC_OVERRIDE:
-                       acpi_legacy_irq(p);
-                       break;
-
-                     case ACPI_ENTRY_PLATFORM_INT_SOURCE:
-                       acpi_platform(p);
-                       break;
-
-                     default:
-                       break;
-               }
+       result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr);
+       if (0 > result) {
+               printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n");
+               return result;
+       }
 
-               /* Move to next table entry. */
-               p += p[1];
+       result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src);
+       if (0 > result) {
+               printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
+               return result;
        }
 
-       /* Make bootup pretty */
-       printk("      %d CPUs available, %d CPUs total\n", available_cpus, total_cpus);
+#ifdef CONFIG_SERIAL_ACPI
+       /*
+        * TBD: Need phased approach to table parsing (only do those absolutely
+        *      required during boot-up).  Recommend expanding concept of fix-
+        *      feature devices (LDM) to include table-based devices such as
+        *      serial ports, EC, SMBus, etc.
+        */
+       acpi_table_parse(ACPI_SPCR, acpi_parse_spcr);
+#endif /*CONFIG_SERIAL_ACPI*/
+
+#ifdef CONFIG_SMP
+       if (available_cpus == 0) {
+               printk("ACPI: Found 0 CPUS; assuming 1\n");
+               available_cpus = 1; /* We've got at least one of these, no? */
+       }
+       smp_boot_data.cpu_count = total_cpus;
+#endif
+       /* Make boot-up look pretty */
+       printk("%d CPUs available, %d CPUs total\n", available_cpus, total_cpus);
+
+       return 0;
 }
 
+
+/* --------------------------------------------------------------------------
+                             PCI Interrupt Routing
+   -------------------------------------------------------------------------- */
+
 int __init
-acpi_parse (acpi_rsdp_t *rsdp)
+acpi_get_prt (struct pci_vector_struct **vectors, int *count)
 {
-# ifdef CONFIG_ACPI
-       acpi_rsdt_t *rsdt;
-       acpi_desc_table_hdr_t *hdrp;
-       long tables, i;
+       struct pci_vector_struct *vector = NULL;
+       struct list_head *node = NULL;
+       struct acpi_prt_entry *entry = NULL;
+       int i = 0;
 
-       if (strncmp(rsdp->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) {
-               printk("Uh-oh, ACPI RSDP signature incorrect!\n");
-               return 0;
-       }
+       if (!vectors || !count)
+               return -EINVAL;
 
-       rsdt = __va(rsdp->rsdt);
-       if (strncmp(rsdt->header.signature, ACPI_RSDT_SIG, ACPI_RSDT_SIG_LEN)) {
-               printk("Uh-oh, ACPI RDST signature incorrect!\n");
-               return 0;
+       *vectors = NULL;
+       *count = 0;
+
+       if (acpi_prts.count < 0) {
+               printk(KERN_ERR PREFIX "No PCI IRQ routing entries\n");
+               return -ENODEV;
        }
 
-       printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id,
-              rsdt->header.oem_revision >> 16, rsdt->header.oem_revision & 0xffff);
+       /* Allocate vectors */
 
-       acpi_cf_init(rsdp);
+       *vectors = kmalloc(sizeof(struct pci_vector_struct) * acpi_prts.count, GFP_KERNEL);
+       if (!(*vectors))
+               return -ENOMEM;
 
-       tables = (rsdt->header.length - sizeof(acpi_desc_table_hdr_t)) / 8;
-       for (i = 0; i < tables; i++) {
-               hdrp = (acpi_desc_table_hdr_t *) __va(rsdt->entry_ptrs[i]);
+       /* Convert PRT entries to IOSAPIC PCI vectors */
 
-               /* Only interested int the MSAPIC table for now ... */
-               if (strncmp(hdrp->signature, ACPI_SAPIC_SIG, ACPI_SAPIC_SIG_LEN) != 0)
-                       continue;
+       vector = *vectors;
 
-               acpi_parse_msapic((acpi_sapic_t *) hdrp);
+       list_for_each(node, &acpi_prts.entries) {
+               entry = (struct acpi_prt_entry *)node;
+               vector[i].bus    = (u16) entry->id.bus;
+               vector[i].pci_id = (u32) entry->id.dev << 16 | 0xffff;
+               vector[i].pin    = (u8)  entry->id.pin;
+               vector[i].irq    = (u8)  entry->source.index;
+               i++;
        }
+       *count = acpi_prts.count;
+       return 0;
+}
 
-       acpi_cf_terminate();
+/* Assume IA64 always use I/O SAPIC */
 
-#  ifdef CONFIG_SMP
-       if (available_cpus == 0) {
-               printk("ACPI: Found 0 CPUS; assuming 1\n");
-               available_cpus = 1; /* We've got at least one of these, no? */
-       }
-       smp_boot_data.cpu_count = total_cpus;
-#  endif
-# endif /* CONFIG_ACPI */
-       return 1;
+int __init
+acpi_get_interrupt_model (int *type)
+{
+        if (!type)
+                return -EINVAL;
+
+       *type = ACPI_INT_MODEL_IOSAPIC;
+
+        return 0;
 }