Hi Graeme,

We may need to fix the compilation error after enabling CONFIG_ACPI_PROCESSOR

  CC      drivers/acpi/processor_idle.o
drivers/acpi/processor_driver.c:51:21: fatal error: asm/cpu.h: No such file or directory
compilation terminated.
make[2]: *** [drivers/acpi/processor_driver.o] Error 1
make[2]: *** Waiting for unfinished jobs....
drivers/acpi/processor_idle.c: In function ‘acpi_safe_halt’:
drivers/acpi/processor_idle.c:123:23: error: ‘struct thread_info’ has no member named ‘status’
drivers/acpi/processor_idle.c:123:36: error: ‘TS_POLLING’ undeclared (first use in this function)
drivers/acpi/processor_idle.c:123:36: note: each undeclared identifier is reported only once for each function it appears in
drivers/acpi/processor_idle.c:130:3: error: implicit declaration of function ‘arch_safe_halt’ [-Werror=implicit-function-declaration]
drivers/acpi/processor_idle.c:133:23: error: ‘struct thread_info’ has no member named ‘status’
drivers/acpi/processor_idle.c: In function ‘acpi_idle_enter_simple’:
drivers/acpi/processor_idle.c:787:24: error: ‘struct thread_info’ has no member named ‘status’
drivers/acpi/processor_idle.c:787:37: error: ‘TS_POLLING’ undeclared (first use in this function)
drivers/acpi/processor_idle.c:795:25: error: ‘struct thread_info’ has no member named ‘status’
drivers/acpi/processor_idle.c:816:24: error: ‘struct thread_info’ has no member named ‘status’
drivers/acpi/processor_idle.c: In function ‘acpi_idle_enter_bm’:
drivers/acpi/processor_idle.c:855:24: error: ‘struct thread_info’ has no member named ‘status’
drivers/acpi/processor_idle.c:855:37: error: ‘TS_POLLING’ undeclared (first use in this function)
drivers/acpi/processor_idle.c:863:25: error: ‘struct thread_info’ has no member named ‘status’
drivers/acpi/processor_idle.c:868:2: error: implicit declaration of function ‘acpi_unlazy_tlb’ [-Werror=implicit-function-declaration]
drivers/acpi/processor_idle.c:912:24: error: ‘struct thread_info’ has no member named ‘status’
drivers/acpi/processor_idle.c: In function ‘acpi_processor_power_init’:
drivers/acpi/processor_idle.c:1172:3: error: implicit declaration of function ‘acpi_processor_cstate_check’ [-Werror=implicit-function-declaration]
cc1: some warnings being treated as errors
make[2]: *** [drivers/acpi/processor_idle.o] Error 1
make[1]: *** [drivers/acpi] Error 2
make: *** [drivers] Error 2

Regards
-Naresh Bhat


On 7 June 2013 20:06, Graeme Gregory <graeme.gregory@linaro.org> wrote:
From: Graeme Gregory <graeme.gregory@linaro.org>

Start of initialisation of ACPI ported over from armv7 tree.

Patch will now reach the magical goal of ACPI: Interpreter enabled

Signed-off-by: Graeme Gregory <graeme.gregory@linaro.org>
---
 arch/arm64/Kconfig                         |    2 +
 arch/arm64/include/asm/acpi.h              |  153 +++
 arch/arm64/include/asm/io.h                |    1 +
 arch/arm64/include/asm/processor.h         |   13 +
 arch/arm64/kernel/Makefile                 |    3 +
 arch/arm64/kernel/acpi/Makefile            |    6 +
 arch/arm64/kernel/acpi/acpi_div_64_by_32.S |  105 ++
 arch/arm64/kernel/acpi/boot.c              | 1582 ++++++++++++++++++++++++++++
 arch/arm64/kernel/acpi/cstate.c            |  210 ++++
 arch/arm64/kernel/acpi/sleep.c             |  126 +++
 arch/arm64/kernel/acpi/sleep.h             |   17 +
 arch/arm64/kernel/acpi/wakeup_32.S         |  100 ++
 arch/arm64/kernel/acpi/wakeup_64.S         |  124 +++
 arch/arm64/kernel/setup.c                  |   19 +
 drivers/acpi/Kconfig                       |   26 +-
 drivers/acpi/Makefile                      |    4 +-
 drivers/acpi/osl.c                         |   77 ++
 drivers/acpi/processor_core.c              |   36 +-
 drivers/acpi/reboot.c                      |   11 +-
 drivers/acpi/scan.c                        |    4 +
 drivers/of/fdt.c                           |   54 +
 drivers/pnp/pnpacpi/rsparser.c             |    2 +
 include/acpi/pdc_arm64.h                   |   39 +
 include/linux/acpi.h                       |    1 +
 include/linux/of_fdt.h                     |    4 +
 25 files changed, 2703 insertions(+), 16 deletions(-)
 create mode 100644 arch/arm64/include/asm/acpi.h
 create mode 100644 arch/arm64/kernel/acpi/Makefile
 create mode 100644 arch/arm64/kernel/acpi/acpi_div_64_by_32.S
 create mode 100644 arch/arm64/kernel/acpi/boot.c
 create mode 100644 arch/arm64/kernel/acpi/cstate.c
 create mode 100644 arch/arm64/kernel/acpi/sleep.c
 create mode 100644 arch/arm64/kernel/acpi/sleep.h
 create mode 100644 arch/arm64/kernel/acpi/wakeup_32.S
 create mode 100644 arch/arm64/kernel/acpi/wakeup_64.S
 create mode 100644 include/acpi/pdc_arm64.h

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 43b0e9f..b795dda 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -238,6 +238,8 @@ source "net/Kconfig"

 source "drivers/Kconfig"

+source "drivers/acpi/Kconfig"
+
 source "fs/Kconfig"

 source "arch/arm64/Kconfig.debug"
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
new file mode 100644
index 0000000..ad578ba
--- /dev/null
+++ b/arch/arm64/include/asm/acpi.h
@@ -0,0 +1,153 @@
+/*
+ *  Copyright (C) 2013, Al Stone <ahs3@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef _ASM_ARM_ACPI_H
+#define _ASM_ARM_ACPI_H
+
+#ifdef __KERNEL__
+
+#include <acpi/pdc_arm64.h>
+
+#include <asm/cacheflush.h>
+
+#include <linux/init.h>
+
+#define COMPILER_DEPENDENT_INT64       long long
+#define COMPILER_DEPENDENT_UINT64      unsigned long long
+
+/*
+ * Calling conventions:
+ *
+ * ACPI_SYSTEM_XFACE        - Interfaces to host OS (handlers, threads)
+ * ACPI_EXTERNAL_XFACE      - External ACPI interfaces
+ * ACPI_INTERNAL_XFACE      - Internal ACPI interfaces
+ * ACPI_INTERNAL_VAR_XFACE  - Internal variable-parameter list interfaces
+ */
+#define ACPI_SYSTEM_XFACE
+#define ACPI_EXTERNAL_XFACE
+#define ACPI_INTERNAL_XFACE
+#define ACPI_INTERNAL_VAR_XFACE
+
+/* Asm macros */
+#define ACPI_ASM_MACROS
+#define BREAKPOINT3
+#define ACPI_DISABLE_IRQS() local_irq_disable()
+#define ACPI_ENABLE_IRQS()  local_irq_enable()
+#define ACPI_FLUSH_CPU_CACHE() flush_cache_all()
+
+#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \
+       asm ("mov       r0, %2\n"                       \
+            "mov       r1, %3\n"                       \
+            "mov       r2, %4\n"                       \
+             "bl        __arm_acpi_div_64_by_32\n"      \
+             "mov       %0, r0\n"                       \
+             "mov       %1, r1\n"                       \
+            : "=r"(q32), "=r"(r32)             /* output operands */   \
+            : "r"(n_hi), "r"(n_lo), "r"(d32)   /* input operands */    \
+            : "r0", "r1", "r2"                 /* clobbered registers */ \
+            )
+
+#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \
+       asm ("mov       r0, %2\n"                       \
+            "mov       r1, %3\n"                       \
+             "and       r2, r0, #1\n"                   \
+             "lsr       r0, r0, #1\n"                   \
+             "lsr       r1, r1, #1\n"                   \
+             "orr       r1, r1, r2, lsl #31\n"          \
+             "mov       %0, r0\n"                       \
+             "mov       %1, r1\n"                       \
+            : "=r"(n_hi), "=r"(n_lo)           /* output operands */   \
+            : "0"(n_hi), "1"(n_lo)             /* input operands */    \
+            : "r0", "r1", "r2"                 /* clobbered registers */ \
+            )
+
+/* Blob handling macros */
+#define        ACPI_BLOB_HEADER_SIZE   8
+
+int __acpi_acquire_global_lock(unsigned int *lock);
+int __acpi_release_global_lock(unsigned int *lock);
+
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
+        ((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
+
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
+        ((Acq) = __acpi_release_global_lock(&facs->global_lock))
+
+/* Basic configuration for ACPI */
+/* BOZO: hardware reduced acpi only? */
+#ifdef CONFIG_ACPI
+extern int acpi_disabled;
+extern int acpi_noirq;
+extern int acpi_pci_disabled;
+extern int acpi_strict;
+
+struct acpi_arm_root {
+        phys_addr_t phys_address;
+        unsigned long size;
+};
+extern struct acpi_arm_root acpi_arm_rsdp_info;
+
+/* Low-level suspend routine. */
+extern int acpi_suspend_lowlevel(void);
+
+/* Physical address to resume after wakeup */
+/* BOZO: was...
+#define acpi_wakeup_address ((unsigned long)(real_mode_header->wakeup_start))
+*/
+#define acpi_wakeup_address (0)
+
+
+static inline void disable_acpi(void)
+{
+       acpi_disabled = 1;
+       acpi_pci_disabled = 1;
+       acpi_noirq = 1;
+}
+
+static inline bool arch_has_acpi_pdc(void)
+{
+       /* BOZO: replace x86 specific-ness here */
+       return 0;       /* always false for now */
+}
+
+static inline void arch_acpi_set_pdc_bits(u32 *buf)
+{
+       /* BOZO: replace x86 specific-ness here */
+}
+
+static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
+static inline void acpi_disable_pci(void)
+{
+       acpi_pci_disabled = 1;
+       acpi_noirq_set();
+}
+
+#else  /* !CONFIG_ACPI */
+#define acpi_disabled 1                /* ACPI sometimes enabled on ARM */
+#define acpi_noirq 1           /* ACPI sometimes enabled on ARM */
+#define acpi_pci_disabled 1     /* ACPI PCI sometimes enabled on ARM */
+#define acpi_strict 1          /* no ACPI spec workarounds on ARM */
+#endif
+
+#endif /*__KERNEL__*/
+
+#endif /*_ASM_ARM_ACPI_H*/
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 2e12258..849af4b 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -232,6 +232,7 @@ extern void __iounmap(volatile void __iomem *addr);
 #define ioremap(addr, size)            __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
 #define ioremap_nocache(addr, size)    __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
 #define ioremap_wc(addr, size)         __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
+#define ioremap_cache(addr, size)      __ioremap((addr), (size), __pgprot(PROT_DEFAULT))
 #define iounmap                                __iounmap

 #define PROT_SECT_DEFAULT      (PMD_TYPE_SECT | PMD_SECT_AF)
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index ab239b2..0cbc1f6 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -155,6 +155,19 @@ static inline void spin_lock_prefetch(const void *x)
        prefetchw(x);
 }

+/*
+ * Not all ARM devices have ACPI, but some do
+ * BOZO: is this correct?
+ */
+#ifdef CONFIG_ACPI
+enum idle_boot_override { IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_NOMWAIT,
+                         IDLE_POLL, IDLE_FORCE_MWAIT };
+
+extern unsigned long   boot_option_idle_override;
+#endif
+
+/* end BOZO */
+
 #define HAVE_ARCH_PICK_MMAP_LAYOUT

 #endif
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 7b4b564..615c672 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -27,3 +27,6 @@ extra-y                                       := $(head-y) vmlinux.lds
 # vDSO - this must be built first to generate the symbol offsets
 $(call objectify,$(arm64-obj-y)): $(obj)/vdso/vdso-offsets.h
 $(obj)/vdso/vdso-offsets.h: $(obj)/vdso
+
+obj-$(CONFIG_ACPI)                     += acpi/
+
diff --git a/arch/arm64/kernel/acpi/Makefile b/arch/arm64/kernel/acpi/Makefile
new file mode 100644
index 0000000..e28c063
--- /dev/null
+++ b/arch/arm64/kernel/acpi/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_ACPI)             += boot.o
+
+# BOZO: need to re-enable this properly
+#obj-$(CONFIG_ACPI_SLEEP)      += sleep.o wakeup_$(BITS).o
+obj-$(CONFIG_ACPI_SLEEP)       += sleep.o
+
diff --git a/arch/arm64/kernel/acpi/acpi_div_64_by_32.S b/arch/arm64/kernel/acpi/acpi_div_64_by_32.S
new file mode 100644
index 0000000..99a14a4
--- /dev/null
+++ b/arch/arm64/kernel/acpi/acpi_div_64_by_32.S
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013, Al Stone <ahs3@redhat.com>
+ *
+ * __acpi_arm_div64_by_32: perform integer division of a 64-bit value
+ *                         a 32-bit value
+ *
+ * The algorithm is borrowed from the GMP library, but has been redone
+ * here in order to put this implementation under a GPLv2 license.
+ *
+ * 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
+ */
+
+#ifdef __ARM_ARCH_8__
+
+#include <linux/linkage.h>
+
+/*
+ * This needs to be called in the following manner:
+ *      n_lo    => r0           # these are the low 32 bits of the dividend
+ *      n_hi    => r1           # the high 32 bits of the dividend
+ *      d32     => r2           # the 32-bit divisor
+ *
+ * The result is:
+ *      q32     <= r0           # the 32-bit quotient
+ *      r32     <= r1           # the 32-bit remainder
+ *
+ * This should be consistent with the normal ARMv7 calling conventions.
+ *
+ */
+
+ENTRY(__arm_acpi_div_64_by_32)
+        mov     r12, #32                // loop counter
+        cmp     r2, #0x80000000         // check divisor MSB and clear carry
+        bcs     bigdiv
+
+loop:   adcs    r1, r1, r1              // handle each bit
+        adc     r0, r0, r0
+        cmp     r0, r2
+        subcs   r0, r0, r2
+        sub     r12, r12, #1
+        teq     r12, #0
+        bne     loop
+
+        mov     r3, r0                  // stash the remainder for a tic
+        adc     r0, r1, r1              // quotient: add in last carry
+        mov     r1, r3                  // remainder (now in right register)
+        mov     pc, lr
+
+bigdiv: stmfd   sp!, { r8, lr }         // clear some scratch space
+
+        and     r8, r1, #1              // save LSB of dividend
+        mov     lr, r0, lsl #31
+        orrs    r1, lr, r1, lsr #1      // r1 = lower part >> 1 bit
+        mov     r0, r0, lsr #1          // r0 = higher part >> 1 bit
+
+        and     lr, r2, #1              // save LSB of divisor
+        movs    r2, r2, lsr #1          // r2 = floor(divisor / 2)
+        adc     r2, r2, #0              // r2 = ceil(divisor / 2)
+
+loop2:  adcs    r1, r1, r1              // handle each bit
+        adc     r0, r0, r0
+        cmp     r0, r2
+        subcs   r0, r0, r2
+        sub     r12, r12, #1
+        teq     r12, #0
+        bne     loop2
+
+        adc     r1, r1, r1              // shift and add last carry
+        add     r0, r8, r0, lsl #1      // shift in remaining dividend LSB
+        tst     lr, lr
+        beq     evendiv
+
+        rsb     r2, lr, r2, lsl #1      // restore divisor value
+        adds    r0, r0, r1              // adjust for omitted divisor LSB
+        addcs   r1, r1, #1              // adjust quotient if a carry results
+        subcs   r0, r0, r2              // adjust remainder, if carry
+        cmp     r0, r2
+        subcs   r0, r0, #1              // adjust remainder
+        addcs   r1, r1, #1              // adjust quotient
+
+evendiv:
+        mov     r3, r0                  // stash the remainder for a tic
+        mov     r0, r1                  // quotient
+        mov     r1, r3                  // remainder
+
+        ldmfd   sp!, { r8, pc }         // restore the registers used
+
+ENDPROC(__arm_acpi_div_64_by_32)
+
+#else           /* ! __ARM_ARCH_7A__ */
+#error  __arm_acpi_div_64_by_32 not defined for this architecture
+#endif
+
diff --git a/arch/arm64/kernel/acpi/boot.c b/arch/arm64/kernel/acpi/boot.c
new file mode 100644
index 0000000..754b747
--- /dev/null
+++ b/arch/arm64/kernel/acpi/boot.c
@@ -0,0 +1,1582 @@
+/*
+ *  boot.c - Architecture-Specific Low-Level ACPI Boot Support
+ *
+ *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *  Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
+ *  Copyright (C) 2013, Al Stone <ahs3@redhat.com> (ARM version)
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+/*
+ * BOZO: this needs to be done right....
+ */
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/acpi_pmtmr.h>
+#include <linux/efi.h>
+#include <linux/cpumask.h>
+#include <linux/memblock.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/slab.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/acpi.h>
+
+static int __initdata acpi_force = 0;
+u32 acpi_rsdt_forced;
+int acpi_disabled = 0;
+EXPORT_SYMBOL(acpi_disabled);
+
+#define BAD_MADT_ENTRY(entry, end) (                                       \
+               (!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
+               ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
+
+#define PREFIX                 "ACPI: "
+
+int acpi_noirq;                                /* skip ACPI IRQ initialization */
+int acpi_pci_disabled;         /* skip ACPI PCI scan and IRQ initialization */
+EXPORT_SYMBOL(acpi_pci_disabled);
+
+int acpi_lapic;
+int acpi_ioapic;
+int acpi_strict;
+
+u8 acpi_sci_flags __initdata;
+int acpi_sci_override_gsi __initdata;
+int acpi_skip_timer_override __initdata;
+int acpi_use_timer_override __initdata;
+int acpi_fix_pin2_polarity __initdata;
+
+struct acpi_arm_root acpi_arm_rsdp_info;     /* info about RSDP from FDT */
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
+#endif
+
+/* --------------------------------------------------------------------------
+                              Boot-time Configuration
+   -------------------------------------------------------------------------- */
+
+/*
+ * The default interrupt routing model is PIC (8259).  This gets
+ * overridden if IOAPICs are enumerated (below).
+ *
+ * Since we're on ARM, it clearly has to be GIC.
+ */
+enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_GIC;
+
+static unsigned int gsi_to_irq(unsigned int gsi)
+{
+       int irq = irq_create_mapping(NULL, gsi);
+
+       return irq;
+}
+
+/*
+ * BOZO: is it reasonable to just reserve the memory space?  Or are there
+ * other restrictions needed?  Or does it need copying to some other place?
+ */
+char *__init __acpi_map_table(unsigned long phys, unsigned long size)
+{
+       if (!phys || !size)
+               return NULL;
+
+       /* we're already in memory so we cannot io_remap the entry */
+        return phys_to_virt(phys);
+}
+
+void __init __acpi_unmap_table(char *map, unsigned long size)
+{
+       if (!map || !size)
+               return;
+
+       /* we're already in memory so we cannot io_remap the entry;
+        * since we're not io_remap'ing, unmap'ing is especially
+        * pointless
+        */
+        return;
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static int __init acpi_parse_madt(struct acpi_table_header *table)
+{
+       struct acpi_table_madt *madt = NULL;
+
+       if (!cpu_has_apic)
+               return -EINVAL;
+
+       madt = (struct acpi_table_madt *)table;
+       if (!madt) {
+               printk(KERN_WARNING PREFIX "Unable to map MADT\n");
+               return -ENODEV;
+       }
+
+       if (madt->address) {
+               acpi_lapic_addr = (u64) madt->address;
+
+               printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n",
+                      madt->address);
+       }
+
+       default_acpi_madt_oem_check(madt->header.oem_id,
+                                   madt->header.oem_table_id);
+
+       return 0;
+}
+
+static void __cpuinit acpi_register_lapic(int id, u8 enabled)
+{
+       unsigned int ver = 0;
+
+       if (id >= (MAX_LOCAL_APIC-1)) {
+               printk(KERN_INFO PREFIX "skipped apicid that is too big\n");
+               return;
+       }
+
+       if (!enabled) {
+               ++disabled_cpus;
+               return;
+       }
+
+       if (boot_cpu_physical_apicid != -1U)
+               ver = apic_version[boot_cpu_physical_apicid];
+
+       generic_processor_info(id, ver);
+}
+
+static int __init
+acpi_parse_x2apic(struct acpi_subtable_header *header, const unsigned long end)
+{
+       struct acpi_madt_local_x2apic *processor = NULL;
+       int apic_id;
+       u8 enabled;
+
+       processor = (struct acpi_madt_local_x2apic *)header;
+
+       if (BAD_MADT_ENTRY(processor, end))
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+       apic_id = processor->local_apic_id;
+       enabled = processor->lapic_flags & ACPI_MADT_ENABLED;
+#ifdef CONFIG_X86_X2APIC
+       /*
+        * We need to register disabled CPU as well to permit
+        * counting disabled CPUs. This allows us to size
+        * cpus_possible_map more accurately, to permit
+        * to not preallocating memory for all NR_CPUS
+        * when we use CPU hotplug.
+        */
+       if (!apic->apic_id_valid(apic_id) && enabled)
+               printk(KERN_WARNING PREFIX "x2apic entry ignored\n");
+       else
+               acpi_register_lapic(apic_id, enabled);
+#else
+       printk(KERN_WARNING PREFIX "x2apic entry ignored\n");
+#endif
+
+       return 0;
+}
+
+static int __init
+acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end)
+{
+       struct acpi_madt_local_apic *processor = NULL;
+
+       processor = (struct acpi_madt_local_apic *)header;
+
+       if (BAD_MADT_ENTRY(processor, end))
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+       /*
+        * We need to register disabled CPU as well to permit
+        * counting disabled CPUs. This allows us to size
+        * cpus_possible_map more accurately, to permit
+        * to not preallocating memory for all NR_CPUS
+        * when we use CPU hotplug.
+        */
+       acpi_register_lapic(processor->id,      /* APIC ID */
+                           processor->lapic_flags & ACPI_MADT_ENABLED);
+
+       return 0;
+}
+
+static int __init
+acpi_parse_sapic(struct acpi_subtable_header *header, const unsigned long end)
+{
+       struct acpi_madt_local_sapic *processor = NULL;
+
+       processor = (struct acpi_madt_local_sapic *)header;
+
+       if (BAD_MADT_ENTRY(processor, end))
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+       acpi_register_lapic((processor->id << 8) | processor->eid,/* APIC ID */
+                           processor->lapic_flags & ACPI_MADT_ENABLED);
+
+       return 0;
+}
+
+static int __init
+acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
+                         const unsigned long end)
+{
+       struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL;
+
+       lapic_addr_ovr = (struct acpi_madt_local_apic_override *)header;
+
+       if (BAD_MADT_ENTRY(lapic_addr_ovr, end))
+               return -EINVAL;
+
+       acpi_lapic_addr = lapic_addr_ovr->address;
+
+       return 0;
+}
+
+static int __init
+acpi_parse_x2apic_nmi(struct acpi_subtable_header *header,
+                     const unsigned long end)
+{
+       struct acpi_madt_local_x2apic_nmi *x2apic_nmi = NULL;
+
+       x2apic_nmi = (struct acpi_madt_local_x2apic_nmi *)header;
+
+       if (BAD_MADT_ENTRY(x2apic_nmi, end))
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+       if (x2apic_nmi->lint != 1)
+               printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n");
+
+       return 0;
+}
+
+static int __init
+acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
+{
+       struct acpi_madt_local_apic_nmi *lapic_nmi = NULL;
+
+       lapic_nmi = (struct acpi_madt_local_apic_nmi *)header;
+
+       if (BAD_MADT_ENTRY(lapic_nmi, end))
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+       if (lapic_nmi->lint != 1)
+               printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n");
+
+       return 0;
+}
+
+#endif                         /*CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_X86_IO_APIC
+
+static int __init
+acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
+{
+       struct acpi_madt_io_apic *ioapic = NULL;
+
+       ioapic = (struct acpi_madt_io_apic *)header;
+
+       if (BAD_MADT_ENTRY(ioapic, end))
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+       mp_register_ioapic(ioapic->id,
+                          ioapic->address, ioapic->global_irq_base);
+
+       return 0;
+}
+
+/*
+ * Parse Interrupt Source Override for the ACPI SCI
+ */
+static void __init acpi_sci_ioapic_setup(u8 bus_irq, u16 polarity, u16 trigger, u32 gsi)
+{
+       if (trigger == 0)       /* compatible SCI trigger is level */
+               trigger = 3;
+
+       if (polarity == 0)      /* compatible SCI polarity is low */
+               polarity = 3;
+
+       /* Command-line over-ride via acpi_sci= */
+       if (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)
+               trigger = (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
+
+       if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK)
+               polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
+
+       /*
+        * mp_config_acpi_legacy_irqs() already setup IRQs < 16
+        * If GSI is < 16, this will update its flags,
+        * else it will create a new mp_irqs[] entry.
+        */
+       mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
+
+       /*
+        * stash over-ride to indicate we've been here
+        * and for later update of acpi_gbl_FADT
+        */
+       acpi_sci_override_gsi = gsi;
+       return;
+}
+
+static int __init
+acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
+                      const unsigned long end)
+{
+       struct acpi_madt_interrupt_override *intsrc = NULL;
+
+       intsrc = (struct acpi_madt_interrupt_override *)header;
+
+       if (BAD_MADT_ENTRY(intsrc, end))
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+       if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) {
+               acpi_sci_ioapic_setup(intsrc->source_irq,
+                                     intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
+                                     (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2,
+                                     intsrc->global_irq);
+               return 0;
+       }
+
+       if (intsrc->source_irq == 0) {
+               if (acpi_skip_timer_override) {
+                       printk(PREFIX "BIOS IRQ0 override ignored.\n");
+                       return 0;
+               }
+
+               if ((intsrc->global_irq == 2) && acpi_fix_pin2_polarity
+                       && (intsrc->inti_flags & ACPI_MADT_POLARITY_MASK)) {
+                       intsrc->inti_flags &= ~ACPI_MADT_POLARITY_MASK;
+                       printk(PREFIX "BIOS IRQ0 pin2 override: forcing polarity to high active.\n");
+               }
+       }
+
+       mp_override_legacy_irq(intsrc->source_irq,
+                               intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
+                               (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2,
+                               intsrc->global_irq);
+
+       return 0;
+}
+
+static int __init
+acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end)
+{
+       struct acpi_madt_nmi_source *nmi_src = NULL;
+
+       nmi_src = (struct acpi_madt_nmi_source *)header;
+
+       if (BAD_MADT_ENTRY(nmi_src, end))
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+       /* TBD: Support nimsrc entries? */
+
+       return 0;
+}
+
+#endif                         /* CONFIG_X86_IO_APIC */
+
+/*
+ * acpi_pic_sci_set_trigger()
+ *
+ * use ELCR to set PIC-mode trigger type for SCI
+ *
+ * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
+ * it may require Edge Trigger -- use "acpi_sci=edge"
+ *
+ * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
+ * for the 8259 PIC.  bit[n] = 1 means irq[n] is Level, otherwise Edge.
+ * ECLR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0)
+ * ECLR2 is IRQs 8-15 (IRQ 8, 13 must be 0)
+ */
+
+void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
+{
+       unsigned int mask = 1 << irq;
+       unsigned int old, new;
+
+       /* Real old ELCR mask */
+       old = inb(0x4d0) | (inb(0x4d1) << 8);
+
+       /*
+        * If we use ACPI to set PCI IRQs, then we should clear ELCR
+        * since we will set it correctly as we enable the PCI irq
+        * routing.
+        */
+       new = acpi_noirq ? old : 0;
+
+       /*
+        * Update SCI information in the ELCR, it isn't in the PCI
+        * routing tables..
+        */
+       switch (trigger) {
+       case 1:         /* Edge - clear */
+               new &= ~mask;
+               break;
+       case 3:         /* Level - set */
+               new |= mask;
+               break;
+       }
+
+       if (old == new)
+               return;
+
+       printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old);
+       outb(new, 0x4d0);
+       outb(new >> 8, 0x4d1);
+}
+
+int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
+{
+       *irq = gsi_to_irq(gsi);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
+
+static int acpi_register_gsi_pic(struct device *dev, u32 gsi,
+                                int trigger, int polarity)
+{
+#ifdef CONFIG_PCI
+       /*
+        * Make sure all (legacy) PCI IRQs are set as level-triggered.
+        */
+       if (trigger == ACPI_LEVEL_SENSITIVE)
+               eisa_set_level_irq(gsi);
+#endif
+
+       return gsi;
+}
+
+static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
+                                   int trigger, int polarity)
+{
+#ifdef CONFIG_X86_IO_APIC
+       gsi = mp_register_gsi(dev, gsi, trigger, polarity);
+#endif
+
+       return gsi;
+}
+
+int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
+                          int trigger, int polarity) = acpi_register_gsi_pic;
+
+/*
+ * success: return IRQ number (>=0)
+ * failure: return < 0
+ */
+int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
+{
+       unsigned int irq;
+       unsigned int plat_gsi = gsi;
+
+       plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity);
+
+       irq = gsi_to_irq(plat_gsi);
+
+       return irq;
+}
+EXPORT_SYMBOL_GPL(acpi_register_gsi);
+
+void acpi_unregister_gsi(u32 gsi)
+{
+}
+EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
+
+void __init acpi_set_irq_model_pic(void)
+{
+       acpi_irq_model = ACPI_IRQ_MODEL_PIC;
+       __acpi_register_gsi = acpi_register_gsi_pic;
+       acpi_ioapic = 0;
+}
+
+void __init acpi_set_irq_model_ioapic(void)
+{
+       acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
+       __acpi_register_gsi = acpi_register_gsi_ioapic;
+       acpi_ioapic = 1;
+}
+
+/*
+ *  ACPI based hotplug support for CPU
+ */
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+#include <acpi/processor.h>
+
+static void __cpuinit acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
+{
+#ifdef CONFIG_ACPI_NUMA
+       int nid;
+
+       nid = acpi_get_node(handle);
+       if (nid == -1 || !node_online(nid))
+               return;
+       set_apicid_to_node(physid, nid);
+       numa_set_node(cpu, nid);
+#endif
+}
+
+static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       struct acpi_madt_local_apic *lapic;
+       cpumask_var_t tmp_map, new_map;
+       u8 physid;
+       int cpu;
+       int retval = -ENOMEM;
+
+       if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
+               return -EINVAL;
+
+       if (!buffer.length || !buffer.pointer)
+               return -EINVAL;
+
+       obj = buffer.pointer;
+       if (obj->type != ACPI_TYPE_BUFFER ||
+           obj->buffer.length < sizeof(*lapic)) {
+               kfree(buffer.pointer);
+               return -EINVAL;
+       }
+
+       lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer;
+
+       if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC ||
+           !(lapic->lapic_flags & ACPI_MADT_ENABLED)) {
+               kfree(buffer.pointer);
+               return -EINVAL;
+       }
+
+       physid = lapic->id;
+
+       kfree(buffer.pointer);
+       buffer.length = ACPI_ALLOCATE_BUFFER;
+       buffer.pointer = NULL;
+       lapic = NULL;
+
+       if (!alloc_cpumask_var(&tmp_map, GFP_KERNEL))
+               goto out;
+
+       if (!alloc_cpumask_var(&new_map, GFP_KERNEL))
+               goto free_tmp_map;
+
+       cpumask_copy(tmp_map, cpu_present_mask);
+#ifdef CONFIG_X86
+        /* BOZO: ?? */
+       acpi_register_lapic(physid, ACPI_MADT_ENABLED);
+#endif
+
+       /*
+        * If acpi_register_lapic successfully generates a new logical cpu
+        * number, then the following will get us exactly what was mapped
+        */
+       cpumask_andnot(new_map, cpu_present_mask, tmp_map);
+       if (cpumask_empty(new_map)) {
+               printk ("Unable to map lapic to logical cpu number\n");
+               retval = -EINVAL;
+               goto free_new_map;
+       }
+
+       acpi_processor_set_pdc(handle);
+
+       cpu = cpumask_first(new_map);
+       acpi_map_cpu2node(handle, cpu, physid);
+
+       *pcpu = cpu;
+       retval = 0;
+
+free_new_map:
+       free_cpumask_var(new_map);
+free_tmp_map:
+       free_cpumask_var(tmp_map);
+out:
+       return retval;
+}
+
+/* wrapper to silence section mismatch warning */
+int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu)
+{
+       return _acpi_map_lsapic(handle, pcpu);
+}
+EXPORT_SYMBOL(acpi_map_lsapic);
+
+int acpi_unmap_lsapic(int cpu)
+{
+#ifdef CONFIG_X86
+        /* BOZO: ??? */
+       per_cpu(x86_cpu_to_apicid, cpu) = -1;
+       set_cpu_present(cpu, false);
+       num_processors--;
+#endif
+
+       return (0);
+}
+
+EXPORT_SYMBOL(acpi_unmap_lsapic);
+#endif                         /* CONFIG_ACPI_HOTPLUG_CPU */
+
+int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
+{
+       /* TBD */
+       return -EINVAL;
+}
+
+EXPORT_SYMBOL(acpi_register_ioapic);
+
+int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
+{
+       /* TBD */
+       return -EINVAL;
+}
+
+EXPORT_SYMBOL(acpi_unregister_ioapic);
+
+static int __init acpi_parse_sbf(struct acpi_table_header *table)
+{
+       struct acpi_table_boot *sb;
+
+       sb = (struct acpi_table_boot *)table;
+       if (!sb) {
+               printk(KERN_WARNING PREFIX "Unable to map SBF\n");
+               return -ENODEV;
+       }
+
+#ifdef CONFIG_X86
+        /* BOZO: can this be ignored?  do we need SBF? */
+       sbf_port = sb->cmos_index;      /* Save CMOS port */
+#endif
+
+       return 0;
+}
+
+#ifdef CONFIG_HPET_TIMER
+#include <asm/hpet.h>
+
+static struct __initdata resource *hpet_res;
+
+static int __init acpi_parse_hpet(struct acpi_table_header *table)
+{
+       struct acpi_table_hpet *hpet_tbl;
+
+       hpet_tbl = (struct acpi_table_hpet *)table;
+       if (!hpet_tbl) {
+               printk(KERN_WARNING PREFIX "Unable to map HPET\n");
+               return -ENODEV;
+       }
+
+       if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
+               printk(KERN_WARNING PREFIX "HPET timers must be located in "
+                      "memory.\n");
+               return -1;
+       }
+
+       hpet_address = hpet_tbl->address.address;
+       hpet_blockid = hpet_tbl->sequence;
+
+       /*
+        * Some broken BIOSes advertise HPET at 0x0. We really do not
+        * want to allocate a resource there.
+        */
+       if (!hpet_address) {
+               printk(KERN_WARNING PREFIX
+                      "HPET id: %#x base: %#lx is invalid\n",
+                      hpet_tbl->id, hpet_address);
+               return 0;
+       }
+#ifdef CONFIG_X86_64
+       /*
+        * Some even more broken BIOSes advertise HPET at
+        * 0xfed0000000000000 instead of 0xfed00000. Fix it up and add
+        * some noise:
+        */
+       if (hpet_address == 0xfed0000000000000UL) {
+               if (!hpet_force_user) {
+                       printk(KERN_WARNING PREFIX "HPET id: %#x "
+                              "base: 0xfed0000000000000 is bogus\n "
+                              "try hpet=force on the kernel command line to "
+                              "fix it up to 0xfed00000.\n", hpet_tbl->id);
+                       hpet_address = 0;
+                       return 0;
+               }
+               printk(KERN_WARNING PREFIX
+                      "HPET id: %#x base: 0xfed0000000000000 fixed up "
+                      "to 0xfed00000.\n", hpet_tbl->id);
+               hpet_address >>= 32;
+       }
+#endif
+       printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
+              hpet_tbl->id, hpet_address);
+
+       /*
+        * Allocate and initialize the HPET firmware resource for adding into
+        * the resource tree during the lateinit timeframe.
+        */
+#define HPET_RESOURCE_NAME_SIZE 9
+       hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);
+
+       hpet_res->name = (void *)&hpet_res[1];
+       hpet_res->flags = IORESOURCE_MEM;
+       snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u",
+                hpet_tbl->sequence);
+
+       hpet_res->start = hpet_address;
+       hpet_res->end = hpet_address + (1 * 1024) - 1;
+
+       return 0;
+}
+
+/*
+ * hpet_insert_resource inserts the HPET resources used into the resource
+ * tree.
+ */
+static __init int hpet_insert_resource(void)
+{
+       if (!hpet_res)
+               return 1;
+
+       return insert_resource(&iomem_resource, hpet_res);
+}
+
+late_initcall(hpet_insert_resource);
+
+#else
+#define        acpi_parse_hpet NULL
+#endif
+
+static int __init acpi_parse_fadt(struct acpi_table_header *table)
+{
+
+#ifdef CONFIG_X86_PM_TIMER
+       /* detect the location of the ACPI PM Timer */
+       if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
+               /* FADT rev. 2 */
+               if (acpi_gbl_FADT.xpm_timer_block.space_id !=
+                   ACPI_ADR_SPACE_SYSTEM_IO)
+                       return 0;
+
+               pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
+               /*
+                * "X" fields are optional extensions to the original V1.0
+                * fields, so we must selectively expand V1.0 fields if the
+                * corresponding X field is zero.
+                */
+               if (!pmtmr_ioport)
+                       pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
+       } else {
+               /* FADT rev. 1 */
+               pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
+       }
+       if (pmtmr_ioport)
+               printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
+                      pmtmr_ioport);
+#endif
+       return 0;
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+/*
+ * Parse LAPIC entries in MADT
+ * returns 0 on success, < 0 on error
+ */
+
+static int __init early_acpi_parse_madt_lapic_addr_ovr(void)
+{
+       int count;
+
+       if (!cpu_has_apic)
+               return -ENODEV;
+
+       /*
+        * Note that the LAPIC address is obtained from the MADT (32-bit value)
+        * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
+        */
+
+       count =
+           acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
+                                 acpi_parse_lapic_addr_ovr, 0);
+       if (count < 0) {
+               printk(KERN_ERR PREFIX
+                      "Error parsing LAPIC address override entry\n");
+               return count;
+       }
+
+       register_lapic_address(acpi_lapic_addr);
+
+       return count;
+}
+
+static int __init acpi_parse_madt_lapic_entries(void)
+{
+       int count;
+       int x2count = 0;
+
+       if (!cpu_has_apic)
+               return -ENODEV;
+
+       /*
+        * Note that the LAPIC address is obtained from the MADT (32-bit value)
+        * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
+        */
+
+       count =
+           acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
+                                 acpi_parse_lapic_addr_ovr, 0);
+       if (count < 0) {
+               printk(KERN_ERR PREFIX
+                      "Error parsing LAPIC address override entry\n");
+               return count;
+       }
+
+       register_lapic_address(acpi_lapic_addr);
+
+       count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC,
+                                     acpi_parse_sapic, MAX_LOCAL_APIC);
+
+       if (!count) {
+               x2count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC,
+                                       acpi_parse_x2apic, MAX_LOCAL_APIC);
+               count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC,
+                                       acpi_parse_lapic, MAX_LOCAL_APIC);
+       }
+       if (!count && !x2count) {
+               printk(KERN_ERR PREFIX "No LAPIC entries present\n");
+               /* TBD: Cleanup to allow fallback to MPS */
+               return -ENODEV;
+       } else if (count < 0 || x2count < 0) {
+               printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n");
+               /* TBD: Cleanup to allow fallback to MPS */
+               return count;
+       }
+
+       x2count =
+           acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC_NMI,
+                                 acpi_parse_x2apic_nmi, 0);
+       count =
+           acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0);
+       if (count < 0 || x2count < 0) {
+               printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
+               /* TBD: Cleanup to allow fallback to MPS */
+               return count;
+       }
+       return 0;
+}
+#endif                         /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_X86_IO_APIC
+#define MP_ISA_BUS             0
+
+#ifdef CONFIG_X86_ES7000
+extern int es7000_plat;
+#endif
+
+void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
+{
+       int ioapic;
+       int pin;
+       struct mpc_intsrc mp_irq;
+
+       /*
+        * Convert 'gsi' to 'ioapic.pin'.
+        */
+       ioapic = mp_find_ioapic(gsi);
+       if (ioapic < 0)
+               return;
+       pin = mp_find_ioapic_pin(ioapic, gsi);
+
+       /*
+        * TBD: This check is for faulty timer entries, where the override
+        *      erroneously sets the trigger to level, resulting in a HUGE
+        *      increase of timer interrupts!
+        */
+       if ((bus_irq == 0) && (trigger == 3))
+               trigger = 1;
+
+       mp_irq.type = MP_INTSRC;
+       mp_irq.irqtype = mp_INT;
+       mp_irq.irqflag = (trigger << 2) | polarity;
+       mp_irq.srcbus = MP_ISA_BUS;
+       mp_irq.srcbusirq = bus_irq;     /* IRQ */
+       mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */
+       mp_irq.dstirq = pin;    /* INTIN# */
+
+       mp_save_irq(&mp_irq);
+
+       isa_irq_to_gsi[bus_irq] = gsi;
+}
+
+void __init mp_config_acpi_legacy_irqs(void)
+{
+       int i;
+       struct mpc_intsrc mp_irq;
+
+#ifdef CONFIG_EISA
+       /*
+        * Fabricate the legacy ISA bus (bus #31).
+        */
+       mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA;
+#endif
+       set_bit(MP_ISA_BUS, mp_bus_not_pci);
+       pr_debug("Bus #%d is ISA\n", MP_ISA_BUS);
+
+#ifdef CONFIG_X86_ES7000
+       /*
+        * Older generations of ES7000 have no legacy identity mappings
+        */
+       if (es7000_plat == 1)
+               return;
+#endif
+
+       /*
+        * Use the default configuration for the IRQs 0-15.  Unless
+        * overridden by (MADT) interrupt source override entries.
+        */
+       for (i = 0; i < 16; i++) {
+               int ioapic, pin;
+               unsigned int dstapic;
+               int idx;
+               u32 gsi;
+
+               /* Locate the gsi that irq i maps to. */
+               if (acpi_isa_irq_to_gsi(i, &gsi))
+                       continue;
+
+               /*
+                * Locate the IOAPIC that manages the ISA IRQ.
+                */
+               ioapic = mp_find_ioapic(gsi);
+               if (ioapic < 0)
+                       continue;
+               pin = mp_find_ioapic_pin(ioapic, gsi);
+               dstapic = mpc_ioapic_id(ioapic);
+
+               for (idx = 0; idx < mp_irq_entries; idx++) {
+                       struct mpc_intsrc *irq = mp_irqs + idx;
+
+                       /* Do we already have a mapping for this ISA IRQ? */
+                       if (irq->srcbus == MP_ISA_BUS && irq->srcbusirq == i)
+                               break;
+
+                       /* Do we already have a mapping for this IOAPIC pin */
+                       if (irq->dstapic == dstapic && irq->dstirq == pin)
+                               break;
+               }
+
+               if (idx != mp_irq_entries) {
+                       printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i);
+                       continue;       /* IRQ already used */
+               }
+
+               mp_irq.type = MP_INTSRC;
+               mp_irq.irqflag = 0;     /* Conforming */
+               mp_irq.srcbus = MP_ISA_BUS;
+               mp_irq.dstapic = dstapic;
+               mp_irq.irqtype = mp_INT;
+               mp_irq.srcbusirq = i; /* Identity mapped */
+               mp_irq.dstirq = pin;
+
+               mp_save_irq(&mp_irq);
+       }
+}
+
+static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
+                       int polarity)
+{
+#ifdef CONFIG_X86_MPPARSE
+       struct mpc_intsrc mp_irq;
+       struct pci_dev *pdev;
+       unsigned char number;
+       unsigned int devfn;
+       int ioapic;
+       u8 pin;
+
+       if (!acpi_ioapic)
+               return 0;
+       if (!dev)
+               return 0;
+       if (dev->bus != &pci_bus_type)
+               return 0;
+
+       pdev = to_pci_dev(dev);
+       number = pdev->bus->number;
+       devfn = pdev->devfn;
+       pin = pdev->pin;
+       /* print the entry should happen on mptable identically */
+       mp_irq.type = MP_INTSRC;
+       mp_irq.irqtype = mp_INT;
+       mp_irq.irqflag = (trigger == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) |
+                               (polarity == ACPI_ACTIVE_HIGH ? 1 : 3);
+       mp_irq.srcbus = number;
+       mp_irq.srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3);
+       ioapic = mp_find_ioapic(gsi);
+       mp_irq.dstapic = mpc_ioapic_id(ioapic);
+       mp_irq.dstirq = mp_find_ioapic_pin(ioapic, gsi);
+
+       mp_save_irq(&mp_irq);
+#endif
+       return 0;
+}
+
+int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
+{
+       int ioapic;
+       int ioapic_pin;
+       struct io_apic_irq_attr irq_attr;
+
+       if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
+               return gsi;
+
+       /* Don't set up the ACPI SCI because it's already set up */
+       if (acpi_gbl_FADT.sci_interrupt == gsi)
+               return gsi;
+
+       ioapic = mp_find_ioapic(gsi);
+       if (ioapic < 0) {
+               printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
+               return gsi;
+       }
+
+       ioapic_pin = mp_find_ioapic_pin(ioapic, gsi);
+
+       if (ioapic_pin > MP_MAX_IOAPIC_PIN) {
+               printk(KERN_ERR "Invalid reference to IOAPIC pin "
+                      "%d-%d\n", mpc_ioapic_id(ioapic),
+                      ioapic_pin);
+               return gsi;
+       }
+
+       if (enable_update_mptable)
+               mp_config_acpi_gsi(dev, gsi, trigger, polarity);
+
+       set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin,
+                            trigger == ACPI_EDGE_SENSITIVE ? 0 : 1,
+                            polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
+       io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr);
+
+       return gsi;
+}
+
+/*
+ * Parse IOAPIC related entries in MADT
+ * returns 0 on success, < 0 on error
+ */
+static int __init acpi_parse_madt_ioapic_entries(void)
+{
+       int count;
+
+       /*
+        * ACPI interpreter is required to complete interrupt setup,
+        * so if it is off, don't enumerate the io-apics with ACPI.
+        * If MPS is present, it will handle them,
+        * otherwise the system will stay in PIC mode
+        */
+       if (acpi_disabled || acpi_noirq)
+               return -ENODEV;
+
+       if (!cpu_has_apic)
+               return -ENODEV;
+
+       /*
+        * if "noapic" boot option, don't look for IO-APICs
+        */
+       if (skip_ioapic_setup) {
+               printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
+                      "due to 'noapic' option.\n");
+               return -ENODEV;
+       }
+
+       count =
+           acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic,
+                                 MAX_IO_APICS);
+       if (!count) {
+               printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
+               return -ENODEV;
+       } else if (count < 0) {
+               printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n");
+               return count;
+       }
+
+       count =
+           acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr,
+                                 nr_irqs);
+       if (count < 0) {
+               printk(KERN_ERR PREFIX
+                      "Error parsing interrupt source overrides entry\n");
+               /* TBD: Cleanup to allow fallback to MPS */
+               return count;
+       }
+
+       /*
+        * If BIOS did not supply an INT_SRC_OVR for the SCI
+        * pretend we got one so we can set the SCI flags.
+        */
+       if (!acpi_sci_override_gsi)
+               acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0,
+                                     acpi_gbl_FADT.sci_interrupt);
+
+       /* Fill in identity legacy mappings where no override */
+       mp_config_acpi_legacy_irqs();
+
+       count =
+           acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src,
+                                 nr_irqs);
+       if (count < 0) {
+               printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
+               /* TBD: Cleanup to allow fallback to MPS */
+               return count;
+       }
+
+       return 0;
+}
+#else
+static inline int acpi_parse_madt_ioapic_entries(void)
+{
+       return -1;
+}
+#endif /* !CONFIG_X86_IO_APIC */
+
+static void __init early_acpi_process_madt(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+       int error;
+
+       if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
+
+               /*
+                * Parse MADT LAPIC entries
+                */
+               error = early_acpi_parse_madt_lapic_addr_ovr();
+               if (!error) {
+                       acpi_lapic = 1;
+                       smp_found_config = 1;
+               }
+               if (error == -EINVAL) {
+                       /*
+                        * Dell Precision Workstation 410, 610 come here.
+                        */
+                       printk(KERN_ERR PREFIX
+                              "Invalid BIOS MADT, disabling ACPI\n");
+                       disable_acpi();
+               }
+       }
+#endif
+}
+
+static void __init acpi_process_madt(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+       int error;
+
+       if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
+
+               /*
+                * Parse MADT LAPIC entries
+                */
+               error = acpi_parse_madt_lapic_entries();
+               if (!error) {
+                       acpi_lapic = 1;
+
+                       /*
+                        * Parse MADT IO-APIC entries
+                        */
+                       error = acpi_parse_madt_ioapic_entries();
+                       if (!error) {
+                               acpi_set_irq_model_ioapic();
+
+                               smp_found_config = 1;
+                       }
+               }
+               if (error == -EINVAL) {
+                       /*
+                        * Dell Precision Workstation 410, 610 come here.
+                        */
+                       printk(KERN_ERR PREFIX
+                              "Invalid BIOS MADT, disabling ACPI\n");
+                       disable_acpi();
+               }
+       } else {
+               /*
+                * ACPI found no MADT, and so ACPI wants UP PIC mode.
+                * In the event an MPS table was found, forget it.
+                * Boot with "acpi=off" to use MPS on such a system.
+                */
+               if (smp_found_config) {
+                       printk(KERN_WARNING PREFIX
+                               "No APIC-table, disabling MPS\n");
+                       smp_found_config = 0;
+               }
+       }
+
+       /*
+        * ACPI supports both logical (e.g. Hyper-Threading) and physical
+        * processors, where MPS only supports physical.
+        */
+       if (acpi_lapic && acpi_ioapic)
+               printk(KERN_INFO "Using ACPI (MADT) for SMP configuration "
+                      "information\n");
+       else if (acpi_lapic)
+               printk(KERN_INFO "Using ACPI for processor (LAPIC) "
+                      "configuration information\n");
+#endif
+       return;
+}
+
+void set_checksum(u8 *start, int len, u8 *cksum)
+{
+       u8 newsum, oldsum;
+       u8 *p;
+
+       newsum = 0;
+       for (p = (u8 *)start; p < (u8 *)(start + len); p++)
+               newsum += *p;
+
+       oldsum = *cksum;
+       newsum = (u8)(newsum - oldsum);
+
+       *cksum = (u8)(0 - newsum);
+}
+
+void __init acpi_arm_blob_relocate(void)
+{
+       /*
+        * Fortunately, there are only a few tables that need to
+        * have their offsets converted to actual addresses.
+        *
+        * NB: all values in the blob are little-endian.
+        */
+
+       struct acpi_table_rsdp *rp;
+       struct acpi_table_xsdt *xp;
+       struct acpi_table_fadt *fp;
+       phys_addr_t paddress;
+       void *vaddress;
+       u32 entries;
+       u32 ii;
+       u64 *tmp;
+
+       if (!acpi_arm_rsdp_info.phys_address && !acpi_arm_rsdp_info.size) {
+               printk(KERN_ERR "(E) ACPI: failed to find rsdp info\n");
+               return;
+       }
+
+       paddress = acpi_arm_rsdp_info.phys_address;
+       paddress += ACPI_BLOB_HEADER_SIZE;
+       vaddress = phys_to_virt(paddress);
+
+       /* fixups for the rsdp */
+       rp = (struct acpi_table_rsdp *)vaddress;
+       if (rp->rsdt_physical_address)
+               rp->rsdt_physical_address += paddress;
+       if (rp->xsdt_physical_address)
+               rp->xsdt_physical_address += paddress;
+       set_checksum((u8 *)rp, rp->length, &(rp->checksum));
+
+       /* fixups for the xsdt */
+       vaddress = phys_to_virt(rp->xsdt_physical_address);
+       xp = (struct acpi_table_xsdt *)vaddress;
+       entries = xp->header.length - sizeof (struct acpi_table_header);
+       entries /= 8;           /* length is in bytes */
+       tmp = (u64 *)(&(xp->table_offset_entry[0]));
+       for (ii = 0; ii < entries; ii++)
+               *tmp++ += paddress;
+       set_checksum((u8 *)xp, xp->header.length, &(xp->header.checksum));
+
+       /* fixups for the fadt */
+       vaddress = phys_to_virt(xp->table_offset_entry[0]);
+       fp = (struct acpi_table_fadt *)vaddress;
+       if (fp->facs)
+               fp->facs += paddress;
+       if (fp->dsdt)
+               fp->dsdt += paddress;
+       if (fp->Xfacs)
+               fp->Xfacs += paddress;
+       if (fp->Xdsdt)
+               fp->Xdsdt += paddress;
+
+       /* Always fix up the checksums since we've changed bits. */
+       set_checksum((u8 *)fp, fp->header.length, &(fp->header.checksum));
+}
+
+/*
+ * ========== OLD COMMENTS FROM x86 =================================
+ * acpi_boot_table_init() and acpi_boot_init()
+ *  called from setup_arch(), always.
+ *     1. checksums all tables
+ *     2. enumerates lapics
+ *     3. enumerates io-apics
+ *
+ * acpi_table_init() is separate to allow reading SRAT without
+ * other side effects.
+ *
+ * side effects of acpi_boot_init:
+ *     acpi_lapic = 1 if LAPIC found
+ *     acpi_ioapic = 1 if IOAPIC found
+ *     if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
+ *     if acpi_blacklisted() acpi_disabled = 1;
+ *     acpi_irq_model=...
+ *     ...
+ * ==================================================================
+ *
+ * We have to approach this a little different on ARMv7.  We are
+ * passed in an ACPI blob and we really have no idea where in RAM
+ * it will be located.  So, what should have been the physical
+ * addresses of other tables cannot really be hardcoded into the
+ * tables.  What we will do is put an offset in the blob that is
+ * the offset from the beginning of the RSDP structure.  However,
+ * what that means is that we have to unpack the blob and do a
+ * bit of fixup work on the offsets to turn them into kernel
+ * virtual addresses so we can pass them on for later use.
+ */
+
+void __init acpi_boot_table_init(void)
+{
+       /*
+        * If acpi_disabled, bail out
+        */
+       if (acpi_disabled)
+               return;
+
+        printk(KERN_DEBUG "acpi: enter acpi_boot_table_init\n");
+
+       /*
+        * Fix up the addresses in the ACPI we've loaded
+        * in.  The blob has them as offsets and we need
+        * actual addresses.
+        */
+       acpi_arm_blob_relocate();
+
+       /*
+        * Initialize the ACPI boot-time table parser.
+        */
+       if (acpi_table_init()) {
+               disable_acpi();
+               return;
+       }
+
+        printk(KERN_INFO "(I) acpi_table_init call completed\n");
+       acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
+
+       /*
+        * blacklist may disable ACPI entirely
+        */
+       if (acpi_blacklisted()) {
+               if (acpi_force) {
+                       printk(KERN_WARNING PREFIX "acpi=force override\n");
+               } else {
+                       printk(KERN_WARNING PREFIX "Disabling ACPI support\n");
+                       disable_acpi();
+                       return;
+               }
+       }
+
+        printk(KERN_INFO "(I) exit acpi_boot_table_init\n");
+}
+
+int __init early_acpi_boot_init(void)
+{
+       /*
+        * If acpi_disabled, bail out
+        */
+       if (acpi_disabled)
+               return 1;
+
+        printk(KERN_INFO "enter early_acpi_boot_init\n");
+
+       /*
+        * Process the Multiple APIC Description Table (MADT), if present
+        */
+       early_acpi_process_madt();
+
+       return 0;
+}
+
+int __init acpi_boot_init(void)
+{
+       /*
+        * If acpi_disabled, bail out
+        */
+       if (acpi_disabled)
+               return 1;
+
+        printk(KERN_INFO "enter acpi_boot_init\n");
+
+       acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
+
+       /*
+        * set sci_int and PM timer address
+        */
+       acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt);
+
+       /*
+        * Process the Multiple APIC Description Table (MADT), if present
+        */
+       acpi_process_madt();
+
+       acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
+
+#ifdef CONFIG_X86
+       if (!acpi_noirq)
+               x86_init.pci.init = pci_acpi_init;
+#endif
+
+       return 0;
+}
+
+static int __init parse_acpi(char *arg)
+{
+       if (!arg)
+               return -EINVAL;
+
+       /* "acpi=off" disables both ACPI table parsing and interpreter */
+       if (strcmp(arg, "off") == 0) {
+               disable_acpi();
+       }
+       /* acpi=force to over-ride black-list */
+       else if (strcmp(arg, "force") == 0) {
+               acpi_force = 1;
+               acpi_disabled = 0;
+       }
+       /* acpi=strict disables out-of-spec workarounds */
+       else if (strcmp(arg, "strict") == 0) {
+               acpi_strict = 1;
+       }
+       /* acpi=rsdt use RSDT instead of XSDT */
+       else if (strcmp(arg, "rsdt") == 0) {
+               acpi_rsdt_forced = 1;
+       }
+       /* "acpi=noirq" disables ACPI interrupt routing */
+       else if (strcmp(arg, "noirq") == 0) {
+               acpi_noirq_set();
+       }
+       /* "acpi=copy_dsdt" copys DSDT */
+       else if (strcmp(arg, "copy_dsdt") == 0) {
+               acpi_gbl_copy_dsdt_locally = 1;
+       } else {
+               /* Core will printk when we return error. */
+               return -EINVAL;
+       }
+       return 0;
+}
+early_param("acpi", parse_acpi);
+
+/* FIXME: Using pci= for an ACPI parameter is a travesty. */
+static int __init parse_pci(char *arg)
+{
+       if (arg && strcmp(arg, "noacpi") == 0)
+               acpi_disable_pci();
+       return 0;
+}
+early_param("pci", parse_pci);
+
+int __init acpi_mps_check(void)
+{
+#if defined(CONFIG_X86_LOCAL_APIC) && !defined(CONFIG_X86_MPPARSE)
+/* mptable code is not built-in*/
+       if (acpi_disabled || acpi_noirq) {
+               printk(KERN_WARNING "MPS support code is not built-in.\n"
+                      "Using acpi=off or acpi=noirq or pci=noacpi "
+                      "may have problem\n");
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+#ifdef CONFIG_X86_IO_APIC
+static int __init parse_acpi_skip_timer_override(char *arg)
+{
+       acpi_skip_timer_override = 1;
+       return 0;
+}
+early_param("acpi_skip_timer_override", parse_acpi_skip_timer_override);
+
+static int __init parse_acpi_use_timer_override(char *arg)
+{
+       acpi_use_timer_override = 1;
+       return 0;
+}
+early_param("acpi_use_timer_override", parse_acpi_use_timer_override);
+#endif /* CONFIG_X86_IO_APIC */
+
+static int __init setup_acpi_sci(char *s)
+{
+       if (!s)
+               return -EINVAL;
+       if (!strcmp(s, "edge"))
+               acpi_sci_flags =  ACPI_MADT_TRIGGER_EDGE |
+                       (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
+       else if (!strcmp(s, "level"))
+               acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL |
+                       (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
+       else if (!strcmp(s, "high"))
+               acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH |
+                       (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
+       else if (!strcmp(s, "low"))
+               acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW |
+                       (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
+       else
+               return -EINVAL;
+       return 0;
+}
+early_param("acpi_sci", setup_acpi_sci);
+
+int __acpi_acquire_global_lock(unsigned int *lock)
+{
+       unsigned int old, new, val;
+       do {
+               old = *lock;
+               new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
+               val = cmpxchg(lock, old, new);
+       } while (unlikely (val != old));
+       return (new < 3) ? -1 : 0;
+}
+
+int __acpi_release_global_lock(unsigned int *lock)
+{
+       unsigned int old, new, val;
+       do {
+               old = *lock;
+               new = old & ~0x3;
+               val = cmpxchg(lock, old, new);
+       } while (unlikely (val != old));
+       return old & 0x1;
+}
+
diff --git a/arch/arm64/kernel/acpi/cstate.c b/arch/arm64/kernel/acpi/cstate.c
new file mode 100644
index 0000000..80d4b3d
--- /dev/null
+++ b/arch/arm64/kernel/acpi/cstate.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2005 Intel Corporation
+ *     Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ *     - Added _PDC for SMP C-states on Intel CPUs
+ */
+
+/* BOZO: i think we just want to ignore C-states for now */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+
+#include <acpi/processor.h>
+#include <asm/acpi.h>
+#ifdef CONFIG_X86
+#include <asm/mwait.h>
+#include <asm/special_insns.h>
+#endif
+
+/*
+ * Initialize bm_flags based on the CPU cache properties
+ * On SMP it depends on cache configuration
+ * - When cache is not shared among all CPUs, we flush cache
+ *   before entering C3.
+ * - When cache is shared among all CPUs, we use bm_check
+ *   mechanism as in UP case
+ *
+ * This routine is called only after all the CPUs are online
+ */
+void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
+                                       unsigned int cpu)
+{
+#ifdef CONFIG_X86
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+       flags->bm_check = 0;
+       if (num_online_cpus() == 1)
+               flags->bm_check = 1;
+       else if (c->x86_vendor == X86_VENDOR_INTEL) {
+               /*
+                * Today all MP CPUs that support C3 share cache.
+                * And caches should not be flushed by software while
+                * entering C3 type state.
+                */
+               flags->bm_check = 1;
+       }
+
+       /*
+        * On all recent Intel platforms, ARB_DISABLE is a nop.
+        * So, set bm_control to zero to indicate that ARB_DISABLE
+        * is not required while entering C3 type state on
+        * P4, Core and beyond CPUs
+        */
+       if (c->x86_vendor == X86_VENDOR_INTEL &&
+           (c->x86 > 0xf || (c->x86 == 6 && c->x86_model >= 0x0f)))
+                       flags->bm_control = 0;
+#endif
+}
+EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
+
+/* The code below handles cstate entry with monitor-mwait pair on Intel*/
+
+struct cstate_entry {
+       struct {
+               unsigned int eax;
+               unsigned int ecx;
+       } states[ACPI_PROCESSOR_MAX_POWER];
+};
+static struct cstate_entry __percpu *cpu_cstate_entry; /* per CPU ptr */
+
+static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
+
+#define NATIVE_CSTATE_BEYOND_HALT      (2)
+
+static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)
+{
+       struct acpi_processor_cx *cx = _cx;
+       long retval;
+       unsigned int eax, ebx, ecx, edx;
+       unsigned int edx_part;
+       unsigned int cstate_type; /* C-state type and not ACPI C-state type */
+       unsigned int num_cstate_subtype;
+
+       cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
+
+       /* Check whether this particular cx_type (in CST) is supported or not */
+       cstate_type = ((cx->address >> MWAIT_SUBSTATE_SIZE) &
+                       MWAIT_CSTATE_MASK) + 1;
+       edx_part = edx >> (cstate_type * MWAIT_SUBSTATE_SIZE);
+       num_cstate_subtype = edx_part & MWAIT_SUBSTATE_MASK;
+
+       retval = 0;
+       if (num_cstate_subtype < (cx->address & MWAIT_SUBSTATE_MASK)) {
+               retval = -1;
+               goto out;
+       }
+
+       /* mwait ecx extensions INTERRUPT_BREAK should be supported for C2/C3 */
+       if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
+           !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) {
+               retval = -1;
+               goto out;
+       }
+
+       if (!mwait_supported[cstate_type]) {
+               mwait_supported[cstate_type] = 1;
+               printk(KERN_DEBUG
+                       "Monitor-Mwait will be used to enter C-%d "
+                       "state\n", cx->type);
+       }
+       snprintf(cx->desc,
+                       ACPI_CX_DESC_LEN, "ACPI FFH INTEL MWAIT 0x%x",
+                       cx->address);
+out:
+       return retval;
+}
+
+int acpi_processor_ffh_cstate_probe(unsigned int cpu,
+               struct acpi_processor_cx *cx, struct acpi_power_register *reg)
+{
+       struct cstate_entry *percpu_entry;
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+       long retval;
+
+       if (!cpu_cstate_entry || c->cpuid_level < CPUID_MWAIT_LEAF)
+               return -1;
+
+       if (reg->bit_offset != NATIVE_CSTATE_BEYOND_HALT)
+               return -1;
+
+       percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
+       percpu_entry->states[cx->index].eax = 0;
+       percpu_entry->states[cx->index].ecx = 0;
+
+       /* Make sure we are running on right CPU */
+
+       retval = work_on_cpu(cpu, acpi_processor_ffh_cstate_probe_cpu, cx);
+       if (retval == 0) {
+               /* Use the hint in CST */
+               percpu_entry->states[cx->index].eax = cx->address;
+               percpu_entry->states[cx->index].ecx = MWAIT_ECX_INTERRUPT_BREAK;
+       }
+
+       /*
+        * For _CST FFH on Intel, if GAS.access_size bit 1 is cleared,
+        * then we should skip checking BM_STS for this C-state.
+        * ref: "Intel Processor Vendor-Specific ACPI Interface Specification"
+        */
+       if ((c->x86_vendor == X86_VENDOR_INTEL) && !(reg->access_size & 0x2))
+               cx->bm_sts_skip = 1;
+
+       return retval;
+}
+EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe);
+
+/*
+ * This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
+ * which can obviate IPI to trigger checking of need_resched.
+ * We execute MONITOR against need_resched and enter optimized wait state
+ * through MWAIT. Whenever someone changes need_resched, we would be woken
+ * up from MWAIT (without an IPI).
+ *
+ * New with Core Duo processors, MWAIT can take some hints based on CPU
+ * capability.
+ */
+void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
+{
+       if (!need_resched()) {
+               if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
+                       clflush((void *)&current_thread_info()->flags);
+
+               __monitor((void *)&current_thread_info()->flags, 0, 0);
+               smp_mb();
+               if (!need_resched())
+                       __mwait(ax, cx);
+       }
+}
+
+void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
+{
+       unsigned int cpu = smp_processor_id();
+       struct cstate_entry *percpu_entry;
+
+       percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
+       mwait_idle_with_hints(percpu_entry->states[cx->index].eax,
+                             percpu_entry->states[cx->index].ecx);
+}
+EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_enter);
+
+static int __init ffh_cstate_init(void)
+{
+       struct cpuinfo_x86 *c = &boot_cpu_data;
+       if (c->x86_vendor != X86_VENDOR_INTEL)
+               return -1;
+
+       cpu_cstate_entry = alloc_percpu(struct cstate_entry);
+       return 0;
+}
+
+static void __exit ffh_cstate_exit(void)
+{
+       free_percpu(cpu_cstate_entry);
+       cpu_cstate_entry = NULL;
+}
+
+arch_initcall(ffh_cstate_init);
+__exitcall(ffh_cstate_exit);
diff --git a/arch/arm64/kernel/acpi/sleep.c b/arch/arm64/kernel/acpi/sleep.c
new file mode 100644
index 0000000..d9d4209
--- /dev/null
+++ b/arch/arm64/kernel/acpi/sleep.c
@@ -0,0 +1,126 @@
+/*
+ * sleep.c - x86-specific ACPI sleep support.
+ *
+ *  Copyright (C) 2001-2003 Patrick Mochel
+ *  Copyright (C) 2001-2003 Pavel Machek <pavel@ucw.cz>
+ */
+
+int acpi_suspend_lowlevel(void)
+{
+        /* BOZO: dummy routine; see below for actual */
+        return 0;
+}
+
+#ifdef CONFIG_X86
+/* BOZO: disable everything for now... */
+
+#include <linux/acpi.h>
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
+#include <linux/dmi.h>
+#include <linux/cpumask.h>
+#include <asm/segment.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+#include <asm/realmode.h>
+
+#include "../../realmode/rm/wakeup.h"
+#include "sleep.h"
+
+unsigned long acpi_realmode_flags;
+
+#if defined(CONFIG_SMP) && defined(CONFIG_64BIT)
+static char temp_stack[4096];
+#endif
+
+/**
+ * acpi_suspend_lowlevel - save kernel state
+ *
+ * Create an identity mapped page table and copy the wakeup routine to
+ * low memory.
+ */
+int acpi_suspend_lowlevel(void)
+{
+       struct wakeup_header *header =
+               (struct wakeup_header *) __va(real_mode_header->wakeup_header);
+
+       if (header->signature != WAKEUP_HEADER_SIGNATURE) {
+               printk(KERN_ERR "wakeup header does not match\n");
+               return -EINVAL;
+       }
+
+       header->video_mode = saved_video_mode;
+
+       header->pmode_behavior = 0;
+
+#ifndef CONFIG_64BIT
+       store_gdt((struct desc_ptr *)&header->pmode_gdt);
+
+       if (!rdmsr_safe(MSR_EFER,
+                       &header->pmode_efer_low,
+                       &header->pmode_efer_high))
+               header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER);
+#endif /* !CONFIG_64BIT */
+
+       header->pmode_cr0 = read_cr0();
+       if (__this_cpu_read(cpu_info.cpuid_level) >= 0) {
+               header->pmode_cr4 = read_cr4();
+               header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
+       }
+       if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
+                       &header->pmode_misc_en_low,
+                       &header->pmode_misc_en_high))
+               header->pmode_behavior |=
+                       (1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE);
+       header->realmode_flags = acpi_realmode_flags;
+       header->real_magic = 0x12345678;
+
+#ifndef CONFIG_64BIT
+       header->pmode_entry = (u32)&wakeup_pmode_return;
+       header->pmode_cr3 = (u32)__pa(&initial_page_table);
+       saved_magic = 0x12345678;
+#else /* CONFIG_64BIT */
+#ifdef CONFIG_SMP
+       stack_start = (unsigned long)temp_stack + sizeof(temp_stack);
+       early_gdt_descr.address =
+                       (unsigned long)get_cpu_gdt_table(smp_processor_id());
+       initial_gs = per_cpu_offset(smp_processor_id());
+#endif
+       initial_code = (unsigned long)wakeup_long64;
+       saved_magic = 0x123456789abcdef0L;
+#endif /* CONFIG_64BIT */
+
+       do_suspend_lowlevel();
+       return 0;
+}
+
+static int __init acpi_sleep_setup(char *str)
+{
+       while ((str != NULL) && (*str != '\0')) {
+               if (strncmp(str, "s3_bios", 7) == 0)
+                       acpi_realmode_flags |= 1;
+               if (strncmp(str, "s3_mode", 7) == 0)
+                       acpi_realmode_flags |= 2;
+               if (strncmp(str, "s3_beep", 7) == 0)
+                       acpi_realmode_flags |= 4;
+#ifdef CONFIG_HIBERNATION
+               if (strncmp(str, "s4_nohwsig", 10) == 0)
+                       acpi_no_s4_hw_signature();
+#endif
+               if (strncmp(str, "nonvs", 5) == 0)
+                       acpi_nvs_nosave();
+               if (strncmp(str, "nonvs_s3", 8) == 0)
+                       acpi_nvs_nosave_s3();
+               if (strncmp(str, "old_ordering", 12) == 0)
+                       acpi_old_suspend_ordering();
+               str = strchr(str, ',');
+               if (str != NULL)
+                       str += strspn(str, ", \t");
+       }
+       return 1;
+}
+
+__setup("acpi_sleep=", acpi_sleep_setup);
+
+#endif
diff --git a/arch/arm64/kernel/acpi/sleep.h b/arch/arm64/kernel/acpi/sleep.h
new file mode 100644
index 0000000..67f59f8c
--- /dev/null
+++ b/arch/arm64/kernel/acpi/sleep.h
@@ -0,0 +1,17 @@
+/*
+ *     Variables and functions used by the code in sleep.c
+ */
+
+#include <asm/realmode.h>
+
+extern unsigned long saved_video_mode;
+extern long saved_magic;
+
+extern int wakeup_pmode_return;
+
+extern u8 wake_sleep_flags;
+
+extern unsigned long acpi_copy_wakeup_routine(unsigned long);
+extern void wakeup_long64(void);
+
+extern void do_suspend_lowlevel(void);
diff --git a/arch/arm64/kernel/acpi/wakeup_32.S b/arch/arm64/kernel/acpi/wakeup_32.S
new file mode 100644
index 0000000..13ab720
--- /dev/null
+++ b/arch/arm64/kernel/acpi/wakeup_32.S
@@ -0,0 +1,100 @@
+       .section .text..page_aligned
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/page_types.h>
+
+# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
+
+       .code32
+       ALIGN
+
+ENTRY(wakeup_pmode_return)
+wakeup_pmode_return:
+       movw    $__KERNEL_DS, %ax
+       movw    %ax, %ss
+       movw    %ax, %ds
+       movw    %ax, %es
+       movw    %ax, %fs
+       movw    %ax, %gs
+
+       # reload the gdt, as we need the full 32 bit address
+       lgdt    saved_gdt
+       lidt    saved_idt
+       lldt    saved_ldt
+       ljmp    $(__KERNEL_CS), $1f
+1:
+       movl    %cr3, %eax
+       movl    %eax, %cr3
+       wbinvd
+
+       # and restore the stack ... but you need gdt for this to work
+       movl    saved_context_esp, %esp
+
+       movl    %cs:saved_magic, %eax
+       cmpl    $0x12345678, %eax
+       jne     bogus_magic
+
+       # jump to place where we left off
+       movl    saved_eip, %eax
+       jmp     *%eax
+
+bogus_magic:
+       jmp     bogus_magic
+
+
+
+save_registers:
+       sgdt    saved_gdt
+       sidt    saved_idt
+       sldt    saved_ldt
+       str     saved_tss
+
+       leal    4(%esp), %eax
+       movl    %eax, saved_context_esp
+       movl    %ebx, saved_context_ebx
+       movl    %ebp, saved_context_ebp
+       movl    %esi, saved_context_esi
+       movl    %edi, saved_context_edi
+       pushfl
+       popl    saved_context_eflags
+
+       movl    $ret_point, saved_eip
+       ret
+
+
+restore_registers:
+       movl    saved_context_ebp, %ebp
+       movl    saved_context_ebx, %ebx
+       movl    saved_context_esi, %esi
+       movl    saved_context_edi, %edi
+       pushl   saved_context_eflags
+       popfl
+       ret
+
+ENTRY(do_suspend_lowlevel)
+       call    save_processor_state
+       call    save_registers
+       pushl   $3
+       call    acpi_enter_sleep_state
+       addl    $4, %esp
+
+#      In case of S3 failure, we'll emerge here.  Jump
+#      to ret_point to recover
+       jmp     ret_point
+       .p2align 4,,7
+ret_point:
+       call    restore_registers
+       call    restore_processor_state
+       ret
+
+.data
+ALIGN
+ENTRY(saved_magic)     .long   0
+ENTRY(saved_eip)       .long   0
+
+# saved registers
+saved_gdt:     .long   0,0
+saved_idt:     .long   0,0
+saved_ldt:     .long   0
+saved_tss:     .long   0
+
diff --git a/arch/arm64/kernel/acpi/wakeup_64.S b/arch/arm64/kernel/acpi/wakeup_64.S
new file mode 100644
index 0000000..8ea5164
--- /dev/null
+++ b/arch/arm64/kernel/acpi/wakeup_64.S
@@ -0,0 +1,124 @@
+.text
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/pgtable_types.h>
+#include <asm/page_types.h>
+#include <asm/msr.h>
+#include <asm/asm-offsets.h>
+
+# Copyright 2003 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
+
+.code64
+       /*
+        * Hooray, we are in Long 64-bit mode (but still running in low memory)
+        */
+ENTRY(wakeup_long64)
+       movq    saved_magic, %rax
+       movq    $0x123456789abcdef0, %rdx
+       cmpq    %rdx, %rax
+       jne     bogus_64_magic
+
+       movw    $__KERNEL_DS, %ax
+       movw    %ax, %ss
+       movw    %ax, %ds
+       movw    %ax, %es
+       movw    %ax, %fs
+       movw    %ax, %gs
+       movq    saved_rsp, %rsp
+
+       movq    saved_rbx, %rbx
+       movq    saved_rdi, %rdi
+       movq    saved_rsi, %rsi
+       movq    saved_rbp, %rbp
+
+       movq    saved_rip, %rax
+       jmp     *%rax
+ENDPROC(wakeup_long64)
+
+bogus_64_magic:
+       jmp     bogus_64_magic
+
+ENTRY(do_suspend_lowlevel)
+       subq    $8, %rsp
+       xorl    %eax, %eax
+       call    save_processor_state
+
+       movq    $saved_context, %rax
+       movq    %rsp, pt_regs_sp(%rax)
+       movq    %rbp, pt_regs_bp(%rax)
+       movq    %rsi, pt_regs_si(%rax)
+       movq    %rdi, pt_regs_di(%rax)
+       movq    %rbx, pt_regs_bx(%rax)
+       movq    %rcx, pt_regs_cx(%rax)
+       movq    %rdx, pt_regs_dx(%rax)
+       movq    %r8, pt_regs_r8(%rax)
+       movq    %r9, pt_regs_r9(%rax)
+       movq    %r10, pt_regs_r10(%rax)
+       movq    %r11, pt_regs_r11(%rax)
+       movq    %r12, pt_regs_r12(%rax)
+       movq    %r13, pt_regs_r13(%rax)
+       movq    %r14, pt_regs_r14(%rax)
+       movq    %r15, pt_regs_r15(%rax)
+       pushfq
+       popq    pt_regs_flags(%rax)
+
+       movq    $resume_point, saved_rip(%rip)
+
+       movq    %rsp, saved_rsp
+       movq    %rbp, saved_rbp
+       movq    %rbx, saved_rbx
+       movq    %rdi, saved_rdi
+       movq    %rsi, saved_rsi
+
+       addq    $8, %rsp
+       movl    $3, %edi
+       xorl    %eax, %eax
+       call    acpi_enter_sleep_state
+       /* in case something went wrong, restore the machine status and go on */
+       jmp     resume_point
+
+       .align 4
+resume_point:
+       /* We don't restore %rax, it must be 0 anyway */
+       movq    $saved_context, %rax
+       movq    saved_context_cr4(%rax), %rbx
+       movq    %rbx, %cr4
+       movq    saved_context_cr3(%rax), %rbx
+       movq    %rbx, %cr3
+       movq    saved_context_cr2(%rax), %rbx
+       movq    %rbx, %cr2
+       movq    saved_context_cr0(%rax), %rbx
+       movq    %rbx, %cr0
+       pushq   pt_regs_flags(%rax)
+       popfq
+       movq    pt_regs_sp(%rax), %rsp
+       movq    pt_regs_bp(%rax), %rbp
+       movq    pt_regs_si(%rax), %rsi
+       movq    pt_regs_di(%rax), %rdi
+       movq    pt_regs_bx(%rax), %rbx
+       movq    pt_regs_cx(%rax), %rcx
+       movq    pt_regs_dx(%rax), %rdx
+       movq    pt_regs_r8(%rax), %r8
+       movq    pt_regs_r9(%rax), %r9
+       movq    pt_regs_r10(%rax), %r10
+       movq    pt_regs_r11(%rax), %r11
+       movq    pt_regs_r12(%rax), %r12
+       movq    pt_regs_r13(%rax), %r13
+       movq    pt_regs_r14(%rax), %r14
+       movq    pt_regs_r15(%rax), %r15
+
+       xorl    %eax, %eax
+       addq    $8, %rsp
+       jmp     restore_processor_state
+ENDPROC(do_suspend_lowlevel)
+
+.data
+ENTRY(saved_rbp)       .quad   0
+ENTRY(saved_rsi)       .quad   0
+ENTRY(saved_rdi)       .quad   0
+ENTRY(saved_rbx)       .quad   0
+
+ENTRY(saved_rip)       .quad   0
+ENTRY(saved_rsp)       .quad   0
+
+ENTRY(saved_magic)     .quad   0
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 6a9a532..250c840 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -41,6 +41,9 @@
 #include <linux/memblock.h>
 #include <linux/of_fdt.h>
 #include <linux/of_platform.h>
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#endif

 #include <asm/cputype.h>
 #include <asm/elf.h>
@@ -54,6 +57,10 @@
 #include <asm/memblock.h>
 #include <asm/psci.h>

+#ifdef CONFIG_ACPI
+#include <asm/acpi.h>
+#endif
+
 unsigned int processor_id;
 EXPORT_SYMBOL(processor_id);

@@ -166,6 +173,10 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)

        /* Retrieve various information from the /chosen node */
        of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
+#ifdef CONFIG_ACPI
+       /* Retrieve ACPI pointers from /chosen node */
+        of_scan_flat_dt(early_init_dt_scan_acpi, &acpi_arm_rsdp_info);
+#endif
        /* Initialize {size,address}-cells info */
        of_scan_flat_dt(early_init_dt_scan_root, NULL);
        /* Setup memory, calling early_init_dt_add_memory_arch */
@@ -264,6 +275,14 @@ void __init setup_arch(char **cmdline_p)
        paging_init();
        request_standard_resources();

+#ifdef CONFIG_ACPI
+       /*
+        * Parse the ACPI tables for possible boot-time configuration
+        */
+       acpi_boot_table_init();
+       early_acpi_boot_init();
+#endif
+
        unflatten_device_tree();

        psci_init();
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 4bf68c8..ef39891 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -5,10 +5,9 @@
 menuconfig ACPI
        bool "ACPI (Advanced Configuration and Power Interface) Support"
        depends on !IA64_HP_SIM
-       depends on IA64 || X86
-       depends on PCI
+       depends on ((IA64 || X86) && PCI) || (ARM || ARM64)
        select PNP
-       default y
+       default y if !(ARM || ARM64)
        help
          Advanced Configuration and Power Interface (ACPI) support for
          Linux requires an ACPI-compliant platform (hardware/firmware),
@@ -46,6 +45,7 @@ config ACPI_SLEEP
 config ACPI_PROCFS
        bool "Deprecated /proc/acpi files"
        depends on PROC_FS
+        depends on IA64 || X86
        help
          For backwards compatibility, this option allows
          deprecated /proc/acpi/ files to exist, even when
@@ -59,6 +59,7 @@ config ACPI_PROCFS
 config ACPI_PROCFS_POWER
        bool "Deprecated power /proc/acpi directories"
        depends on PROC_FS
+        depends on IA64 || X86
        help
          For backwards compatibility, this option allows
           deprecated power /proc/acpi/ directories to exist, even when
@@ -94,6 +95,7 @@ config ACPI_EC_DEBUGFS
 config ACPI_PROC_EVENT
        bool "Deprecated /proc/acpi/event support"
        depends on PROC_FS
+        depends on IA64 || X86
        default y
        help
          A user-space daemon, acpid, typically reads /proc/acpi/event
@@ -111,9 +113,9 @@ config ACPI_PROC_EVENT

 config ACPI_AC
        tristate "AC Adapter"
-       depends on X86
+       depends on X86 || (ARM || ARM64)
        select POWER_SUPPLY
-       default y
+       default y if !(ARM || ARM64)
        help
          This driver supports the AC Adapter object, which indicates
          whether a system is on AC or not.  If you have a system that can
@@ -124,9 +126,9 @@ config ACPI_AC

 config ACPI_BATTERY
        tristate "Battery"
-       depends on X86
+       depends on X86 || (ARM || ARM64)
        select POWER_SUPPLY
-       default y
+       default y if !(ARM || ARM64)
        help
          This driver adds support for battery information through
          /proc/acpi/battery. If you have a mobile system with a battery,
@@ -150,7 +152,8 @@ config ACPI_BUTTON

 config ACPI_VIDEO
        tristate "Video"
-       depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
+       depends on (X86 || (ARM || ARM64)) && \
+                   BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
        depends on INPUT
        select THERMAL
        help
@@ -220,7 +223,7 @@ config ACPI_HOTPLUG_CPU
 config ACPI_PROCESSOR_AGGREGATOR
        tristate "Processor Aggregator"
        depends on ACPI_PROCESSOR
-       depends on X86
+       depends on X86 || (ARM || ARM64)
        help
          ACPI 4.0 defines processor Aggregator, which enables OS to perform
          specific processor configuration and control that applies to all
@@ -245,7 +248,7 @@ config ACPI_THERMAL
 config ACPI_NUMA
        bool "NUMA support"
        depends on NUMA
-       depends on (X86 || IA64)
+       depends on (X86 || IA64 || ARM64)
        default y if IA64_GENERIC || IA64_SGI_SN2

 config ACPI_CUSTOM_DSDT_FILE
@@ -309,6 +312,7 @@ config ACPI_DEBUG_FUNC_TRACE
 config ACPI_PCI_SLOT
        bool "PCI slot detection driver"
        depends on SYSFS
+       depends on PCI
        default n
        help
          This driver creates entries in /sys/bus/pci/slots/ for all PCI
@@ -363,7 +367,7 @@ config ACPI_HOTPLUG_MEMORY

 config ACPI_SBS
        tristate "Smart Battery System"
-       depends on X86
+       depends on X86 || (ARM || ARM64)
        select POWER_SUPPLY
        help
          This driver supports the Smart Battery System, another
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 474fcfe..3dc16fb 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -9,7 +9,7 @@ ccflags-$(CONFIG_ACPI_DEBUG)    += -DACPI_DEBUG_OUTPUT
 # ACPI Boot-Time Table Parsing
 #
 obj-y                          += tables.o
-obj-$(CONFIG_X86)              += blacklist.o
+obj-$(CONFIG_ACPI)             += blacklist.o

 #
 # ACPI Core Subsystem (Interpreter)
@@ -37,7 +37,7 @@ acpi-y                                += resource.o
 acpi-y                         += processor_core.o
 acpi-y                         += ec.o
 acpi-$(CONFIG_ACPI_DOCK)       += dock.o
-acpi-y                         += pci_root.o pci_link.o pci_irq.o
+acpi-$(CONFIG_PCI)             += pci_root.o pci_link.o pci_irq.o
 acpi-y                         += csrt.o
 acpi-y                         += acpi_platform.o
 acpi-y                         += power.o
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 586e7e9..351edf0 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -242,6 +242,67 @@ static int __init setup_acpi_rsdp(char *arg)
 early_param("acpi_rsdp", setup_acpi_rsdp);
 #endif

+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+#include <asm/byteorder.h>
+#include <asm/acpi.h>
+#include <acpi/actbl.h>
+
+void acpi_find_arm_root_pointer(acpi_physical_address *pa)
+{
+        /* BOZO: temporarily clunky.
+         * What we do is, while using u-boot still, is use the values
+         * that have already been retrieved from the FDT node
+         * (/chosen/linux,acpi-start and /chosen/linux,acpi-len) which
+         * contain the address of the first byte of the RSDP after it
+         * has been loaded into RAM during u-boot (e.g., using something
+         * like fatload mmc 0:2 42008000 my.blob), and the size of the
+         * data in the complete ACPI blob.  We only do this since we have
+         * to collaborate with FDT so we have to load FDT and the ACPI
+         * tables in but only have one address we can use via bootm.
+         * With UEFI, we should just be able to use the efi_enabled
+         * branch below in acpi_os_get_root_pointer().
+         */
+
+        void *address;
+        struct acpi_table_rsdp *rp;
+
+        if (!acpi_arm_rsdp_info.phys_address && !acpi_arm_rsdp_info.size) {
+                printk(KERN_ERR "(E) ACPI: failed to find rsdp info\n");
+                *pa = (acpi_physical_address)NULL;
+                return;
+        }
+
+        address = phys_to_virt(acpi_arm_rsdp_info.phys_address);
+       address += ACPI_BLOB_HEADER_SIZE;
+        *pa = (acpi_physical_address)address;
+
+        rp = (struct acpi_table_rsdp *)address;
+        printk(KERN_DEBUG "(I) ACPI rsdp rp: 0x%08lx\n", (long unsigned int)rp);
+        if (rp) {
+                printk(KERN_DEBUG "(I) ACPI rsdp content:\n");
+                printk(KERN_DEBUG "(I)    signature: %.8s\n", rp->signature);
+                printk(KERN_DEBUG "(I)    checksum: 0x%02x\n", rp->checksum);
+                printk(KERN_DEBUG "(I)    oem_id: %.6s\n", rp->oem_id);
+                printk(KERN_DEBUG "(I)    revision: %d\n", rp->revision);
+                printk(KERN_DEBUG "(I)    rsdt: 0x%08lX\n",
+                                  (long unsigned int)rp->rsdt_physical_address);
+                printk(KERN_DEBUG "(I)    length: %d\n", rp->length);
+                printk(KERN_DEBUG "(I)    xsdt: 0x%016llX\n",
+                                 (u64)rp->xsdt_physical_address);
+                printk(KERN_DEBUG "(I)    x_checksum: 0x%02x\n",
+                                  rp->extended_checksum);
+
+                *pa = (acpi_physical_address)(virt_to_phys(rp));
+        }
+        else {
+                printk(KERN_ERR "(E) ACPI missing rsdp info\n");
+                *pa = (acpi_physical_address)NULL;
+        }
+
+        return;
+}
+#endif
+
 acpi_physical_address __init acpi_os_get_root_pointer(void)
 {
 #ifdef CONFIG_KEXEC
@@ -262,7 +323,11 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
        } else {
                acpi_physical_address pa = 0;

+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+                acpi_find_arm_root_pointer(&pa);
+#else
                acpi_find_root_pointer(&pa);
+#endif
                return pa;
        }
 }
@@ -1030,9 +1095,16 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
                return AE_ERROR;
        }

+#ifdef CONFIG_X86
+        /* BOZO: probably should not call this function at all
+         * if there is no PCI... */
        result = raw_pci_read(pci_id->segment, pci_id->bus,
                                PCI_DEVFN(pci_id->device, pci_id->function),
                                reg, size, &value32);
+#else
+        result = 0;
+        value32 = 0;
+#endif
        *value = value32;

        return (result ? AE_ERROR : AE_OK);
@@ -1058,9 +1130,14 @@ acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
                return AE_ERROR;
        }

+#ifdef CONFIG_X86
+        /* BOZO: how do we handle not having PCI? */
        result = raw_pci_write(pci_id->segment, pci_id->bus,
                                PCI_DEVFN(pci_id->device, pci_id->function),
                                reg, size, value);
+#else
+        result = 0;
+#endif

        return (result ? AE_ERROR : AE_OK);
 }
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 164d495..1d9033d 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -90,6 +90,22 @@ static int map_lsapic_id(struct acpi_subtable_header *entry,
        return 1;
 }

+static int map_gic_id(struct acpi_subtable_header *entry,
+                u32 acpi_id, int *apic_id)
+{
+       struct acpi_madt_generic_interrupt *gic =
+               (struct acpi_madt_generic_interrupt *)entry;
+
+       if (!(gic->flags & ACPI_MADT_ENABLED))
+               return 0;
+
+       if (gic->uid != acpi_id)
+               return 0;
+
+       *apic_id = gic->gic_id;
+       return 1;
+}
+
 static int map_madt_entry(int type, u32 acpi_id)
 {
        unsigned long madt_end, entry;
@@ -125,7 +141,10 @@ static int map_madt_entry(int type, u32 acpi_id)
                } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
                        if (map_lsapic_id(header, type, acpi_id, &apic_id))
                                break;
-               }
+               } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
+                       if (map_gic_id(header, acpi_id, &apic_id))
+                                break;
+               }
                entry += header->length;
        }
        return apic_id;
@@ -155,6 +174,8 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
                map_lapic_id(header, acpi_id, &apic_id);
        } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
                map_lsapic_id(header, type, acpi_id, &apic_id);
+       } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
+               map_gic_id(header, acpi_id, &apic_id);
        }

 exit:
@@ -199,6 +220,16 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
                        return apic_id;
        }

+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+       return apic_id;
+       /*
+        * BOZO: need to abstract this out to have it make sense --
+         * it's not that ARM has no equivalent, it's that apic_id is
+        * arch-specific
+        */
+
+#else
+
 #ifdef CONFIG_SMP
        for_each_possible_cpu(i) {
                if (cpu_physical_id(i) == apic_id)
@@ -209,6 +240,9 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
        if (apic_id == 0)
                return apic_id;
 #endif
+
+#endif
+
        return -1;
 }
 EXPORT_SYMBOL_GPL(acpi_get_cpuid);
diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c
index a6c77e8b..410d0be 100644
--- a/drivers/acpi/reboot.c
+++ b/drivers/acpi/reboot.c
@@ -6,9 +6,7 @@
 void acpi_reboot(void)
 {
        struct acpi_generic_address *rr;
-       struct pci_bus *bus0;
        u8 reset_value;
-       unsigned int devfn;

        if (acpi_disabled)
                return;
@@ -31,7 +29,15 @@ void acpi_reboot(void)
        /* The reset register can only exist in I/O, Memory or PCI config space
         * on a device on bus 0. */
        switch (rr->space_id) {
+/*
+ * There are some rare cases in the ARM world with PCI is not one
+ * of the buses available to us, even though we use ACPI.
+ */
+#ifdef CONFIG_PCI
        case ACPI_ADR_SPACE_PCI_CONFIG:
+               struct pci_bus *bus0;
+               unsigned int devfn;
+
                /* The reset register can only live on bus 0. */
                bus0 = pci_find_bus(0, 0);
                if (!bus0)
@@ -44,6 +50,7 @@ void acpi_reboot(void)
                pci_bus_write_config_byte(bus0, devfn,
                                (rr->address & 0xffff), reset_value);
                break;
+#endif

        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
        case ACPI_ADR_SPACE_SYSTEM_IO:
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 5e7e991..97b9227 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1785,8 +1785,10 @@ int __init acpi_scan_init(void)
                printk(KERN_ERR PREFIX "Could not register bus type\n");
        }

+#if defined(CONFIG_PCI)
        acpi_pci_root_init();
        acpi_pci_link_init();
+#endif
        acpi_platform_init();
        acpi_csrt_init();
        acpi_container_init();
@@ -1812,7 +1814,9 @@ int __init acpi_scan_init(void)

        acpi_update_all_gpes();

+#if defined(CONFIG_PCI)
        acpi_pci_root_hp_init();
+#endif

  out:
        mutex_unlock(&acpi_scan_lock);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 808be06..61a032c 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -25,6 +25,10 @@

 #include <asm/page.h>

+#ifdef CONFIG_ACPI
+#include <asm/io.h>
+#endif
+
 char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
 {
        return ((char *)blob) +
@@ -696,6 +700,56 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
        return 1;
 }

+#if (defined(CONFIG_ARM64) || defined (CONFIG_ARM)) && defined(CONFIG_ACPI)
+#include <linux/memblock.h>
+#include <linux/acpi.h>
+#include <asm/acpi.h>
+#include <acpi/actbl.h>
+
+int __init early_init_dt_scan_acpi(unsigned long node, const char *uname,
+                                  int depth, void *data)
+{
+       unsigned long l;
+        unsigned int *p;
+        struct acpi_arm_root *pinfo;
+        unsigned char *sig;
+
+       pr_debug("search \"chosen\" for acpi info, depth: %d, uname: %s\n",
+                 depth, uname);
+
+       if (depth != 1 || !data ||
+           (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
+               return 0;
+
+       /* Retrieve acpi,address line */
+        pinfo = (struct acpi_arm_root *)data;
+       p = of_get_flat_dt_prop(node, "linux,acpi-start", &l);
+       if (p != NULL && l > 0)
+                pinfo->phys_address = be32_to_cpu(*p);
+
+       /* Retrieve acpi,size line */
+       p = of_get_flat_dt_prop(node, "linux,acpi-len", &l);
+       if (p != NULL && l > 0)
+                pinfo->size = be32_to_cpu(*p);
+
+       printk("acpi: start info is 0x%016llX, %lu bytes\n",
+                 pinfo->phys_address, pinfo->size);
+
+       memblock_reserve(pinfo->phys_address, pinfo->size);
+
+        sig = phys_to_virt(pinfo->phys_address);
+
+        printk("acpi: sig is \"%c%c%c%c\"\n",
+               sig[0], sig[1], sig[2], sig[3]);
+        printk("acpi: info is %02x %02x %02x %02x\n",
+               sig[4], sig[5], sig[6], sig[7]);
+        printk("acpi: first table is \"%c%c%c%c\"\n",
+               sig[8], sig[9], sig[10], sig[11]);
+
+       return 1;
+}
+#endif
+
 /**
  * unflatten_device_tree - create tree of device_nodes from flat blob
  *
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index b8f4ea7..464f8c9 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -113,8 +113,10 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master,

 static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r)
 {
+#ifdef CONFIG_PCI
        if (!(r->flags & IORESOURCE_DISABLED))
                pcibios_penalize_isa_irq(r->start, 1);
+#endif

        pnp_add_resource(dev, r);
 }
diff --git a/include/acpi/pdc_arm64.h b/include/acpi/pdc_arm64.h
new file mode 100644
index 0000000..ac8f197
--- /dev/null
+++ b/include/acpi/pdc_arm64.h
@@ -0,0 +1,39 @@
+
+/* _PDC bit definition for ARMv7 processors */
+
+#ifndef __PDC_ARM_H__
+#define __PDC_ARM_H__
+
+/* BOZO: is this even necessary? */
+
+/* _PDC bit definition for ARM processors */
+
+#define ACPI_PDC_P_FFH                 (0x0001)
+#define ACPI_PDC_C_C1_HALT             (0x0002)
+#define ACPI_PDC_T_FFH                 (0x0004)
+#define ACPI_PDC_SMP_C1PT              (0x0008)
+#define ACPI_PDC_SMP_C2C3              (0x0010)
+#define ACPI_PDC_SMP_P_SWCOORD         (0x0020)
+#define ACPI_PDC_SMP_C_SWCOORD         (0x0040)
+#define ACPI_PDC_SMP_T_SWCOORD         (0x0080)
+#define ACPI_PDC_C_C1_FFH              (0x0100)
+#define ACPI_PDC_C_C2C3_FFH            (0x0200)
+#define ACPI_PDC_SMP_P_HWCOORD         (0x0800)
+
+#define ACPI_PDC_EST_CAPABILITY_SMP    (ACPI_PDC_SMP_C1PT | \
+                                        ACPI_PDC_C_C1_HALT | \
+                                        ACPI_PDC_P_FFH)
+
+#define ACPI_PDC_EST_CAPABILITY_SWSMP  (ACPI_PDC_SMP_C1PT | \
+                                        ACPI_PDC_C_C1_HALT | \
+                                        ACPI_PDC_SMP_P_SWCOORD | \
+                                        ACPI_PDC_SMP_P_HWCOORD | \
+                                        ACPI_PDC_P_FFH)
+
+#define ACPI_PDC_C_CAPABILITY_SMP      (ACPI_PDC_SMP_C2C3  | \
+                                        ACPI_PDC_SMP_C1PT  | \
+                                        ACPI_PDC_C_C1_HALT | \
+                                        ACPI_PDC_C_C1_FFH  | \
+                                        ACPI_PDC_C_C2C3_FFH)
+
+#endif                         /* __PDC_ARM_H__ */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index bcbdd74..893670e 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -49,6 +49,7 @@ enum acpi_irq_model_id {
        ACPI_IRQ_MODEL_IOAPIC,
        ACPI_IRQ_MODEL_IOSAPIC,
        ACPI_IRQ_MODEL_PLATFORM,
+       ACPI_IRQ_MODEL_GIC,
        ACPI_IRQ_MODEL_COUNT
 };

diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index ed136ad..98c1029 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -93,6 +93,10 @@ extern unsigned long of_get_flat_dt_root(void);

 extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
                                     int depth, void *data);
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+extern int early_init_dt_scan_acpi(unsigned long node, const char *uname,
+                                  int depth, void *data);
+#endif
 extern void early_init_dt_check_for_initrd(unsigned long node);
 extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
                                     int depth, void *data);
--
1.7.10.4


_______________________________________________
Linaro-acpi mailing list
Linaro-acpi@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-acpi