Hi,
I have managed to get us to boot as far as the dreaded
ACPI: Interpreter enabled
state on armv8 now.
For now ACPI tables cannot be bigger than 1MB in size (we are nowhere near this size). And also FDT cannot be bigger than 1MB (still nowhere near).
From the conversion which was mostly changing
u32 -> void * u32 -> phys_addr_t
and adding the correct initialisation to the setup.c on armv8 it is becoming clear that with the correct universal types used that the arch/arm/kernel/acpi and arch/arm64/kernel/acpi are actually mostly generic to both platforms so we will need to decide where to put them.
This genericness is nice to have as it means we should be able to switch v7/v8 at will for testing!
There is still some code from armv7 that I have not yet brought over to v8 and someone fluent in v8 assembler needs to fix the two assembly bits.
I shall continue to bring code over and enable more ACPI features.
Graeme
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 *)¤t_thread_info()->flags); + + __monitor((void *)¤t_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);
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 *)¤t_thread_info()->flags);
__monitor((void *)¤t_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
Graeme,
thanks, nice use of the #define with inline assembly to avoid the extra cost of using the frame that the five parameters would mandate with the ARM procedure call standard!
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf
Bye Andrea
Sent from my iPad
On 07/giu/2013, at 16:37, 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.
- checksums all tables
- enumerates lapics
- 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 *)¤t_thread_info()->flags);
__monitor((void *)¤t_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
help For backwards compatibility, this option allows deprecated /proc/acpi/ files to exist, even whendepends on IA64 || X86
@@ -59,6 +59,7 @@ config ACPI_PROCFS config ACPI_PROCFS_POWER bool "Deprecated power /proc/acpi directories" depends on PROC_FS
help For backwards compatibility, this option allows deprecated power /proc/acpi/ directories to exist, even whendepends on IA64 || X86
@@ -94,6 +95,7 @@ config ACPI_EC_DEBUGFS config ACPI_PROC_EVENT bool "Deprecated /proc/acpi/event support" depends on PROC_FS
default y help A user-space daemon, acpid, typically reads /proc/acpi/eventdepends on IA64 || X86
@@ -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)) && \
depends on INPUT select THERMAL helpBACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
@@ -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
result = raw_pci_read(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, &value32);* if there is no PCI... */
+#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
result = raw_pci_write(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, value);/* BOZO: how do we handle not having PCI? */
+#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;
} return apic_id;} entry += header->length;
@@ -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
ops, actually all credit goes to Al for the assembly :-)
by the way, would it be possible to replace Al redhat email address with the one @linaro.org?
Thanks!
Andrea
Sent from my iPad
On 09/giu/2013, at 15:45, Andrea Gallo andrea.gallo@linaro.org wrote:
Graeme,
thanks, nice use of the #define with inline assembly to avoid the extra cost of using the frame that the five parameters would mandate with the ARM procedure call standard!
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf
Bye Andrea
Sent from my iPad
On 07/giu/2013, at 16:37, 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.
- checksums all tables
- enumerates lapics
- 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 *)¤t_thread_info()->flags);
__monitor((void *)¤t_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
help For backwards compatibility, this option allows deprecated /proc/acpi/ files to exist, even whendepends on IA64 || X86
@@ -59,6 +59,7 @@ config ACPI_PROCFS config ACPI_PROCFS_POWER bool "Deprecated power /proc/acpi directories" depends on PROC_FS
help For backwards compatibility, this option allows deprecated power /proc/acpi/ directories to exist, even whendepends on IA64 || X86
@@ -94,6 +95,7 @@ config ACPI_EC_DEBUGFS config ACPI_PROC_EVENT bool "Deprecated /proc/acpi/event support" depends on PROC_FS
default y help A user-space daemon, acpid, typically reads /proc/acpi/eventdepends on IA64 || X86
@@ -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)) && \
depends on INPUT select THERMAL helpBACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
@@ -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
result = raw_pci_read(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, &value32);* if there is no PCI... */
+#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
result = raw_pci_write(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, value);/* BOZO: how do we handle not having PCI? */
+#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;
} return apic_id;} entry += header->length;
@@ -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
Hi Andrea,
Yes Al came up with the assembly, now we need the 64bit version :-)
There is no technical reason we cannot change the email addresses, I can do this easilly enough when I do proper patch series beyond WIP ones.
Graeme
On Sun, Jun 09, 2013 at 03:50:50PM +0200, Andrea Gallo wrote:
ops, actually all credit goes to Al for the assembly :-)
by the way, would it be possible to replace Al redhat email address with the one @linaro.org?
Thanks!
Andrea
Sent from my iPad
On 09/giu/2013, at 15:45, Andrea Gallo andrea.gallo@linaro.org wrote:
Graeme,
thanks, nice use of the #define with inline assembly to avoid the extra cost of using the frame that the five parameters would mandate with the ARM procedure call standard!
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf
Bye Andrea
Sent from my iPad
On 07/giu/2013, at 16:37, 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.
- checksums all tables
- enumerates lapics
- 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 *)¤t_thread_info()->flags);
__monitor((void *)¤t_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
help For backwards compatibility, this option allows deprecated /proc/acpi/ files to exist, even whendepends on IA64 || X86
@@ -59,6 +59,7 @@ config ACPI_PROCFS config ACPI_PROCFS_POWER bool "Deprecated power /proc/acpi directories" depends on PROC_FS
help For backwards compatibility, this option allows deprecated power /proc/acpi/ directories to exist, even whendepends on IA64 || X86
@@ -94,6 +95,7 @@ config ACPI_EC_DEBUGFS config ACPI_PROC_EVENT bool "Deprecated /proc/acpi/event support" depends on PROC_FS
default y help A user-space daemon, acpid, typically reads /proc/acpi/eventdepends on IA64 || X86
@@ -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)) && \
depends on INPUT select THERMAL helpBACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
@@ -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
result = raw_pci_read(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, &value32);* if there is no PCI... */
+#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
result = raw_pci_write(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, value);/* BOZO: how do we handle not having PCI? */
+#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;
} return apic_id;} entry += header->length;
@@ -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
On 06/10/2013 02:18 AM, Graeme Gregory wrote:
Hi Andrea,
Yes Al came up with the assembly, now we need the 64bit version :-)
Heh. Yeah, I'll get on the 64-bit versions of these; they are always needed by the OSPM layer in ACPICA for any port but I'm thinking they should be _much_ easier on an actual 64-bit machine :).
And actually, I cannot claim full credit for these. Google helped a great deal and I ended up piecing together a couple of bits of code to get these to work...but yeah, I did think about making it a call but that just seemed wasteful :).