aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-24 11:23:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-24 11:23:45 -0400
commit836ee4874e201a5907f9658fb2bf3527dd952d30 (patch)
tree34a9e521bbba61d127794278e7b14d96797273f4 /arch/arm64
parentfb65d872d7a8dc629837a49513911d0281577bfd (diff)
parent7676fa70feb2f3bcdd4b854a553a57d8ef8505aa (diff)
Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull initial ACPI support for arm64 from Will Deacon: "This series introduces preliminary ACPI 5.1 support to the arm64 kernel using the "hardware reduced" profile. We don't support any peripherals yet, so it's fairly limited in scope: - MEMORY init (UEFI) - ACPI discovery (RSDP via UEFI) - CPU init (FADT) - GIC init (MADT) - SMP boot (MADT + PSCI) - ACPI Kconfig options (dependent on EXPERT) ACPI for arm64 has been in development for a while now and hardware has been available that can boot with either FDT or ACPI tables. This has been made possible by both changes to the ACPI spec to cater for ARM-based machines (known as "hardware-reduced" in ACPI parlance) but also a Linaro-driven effort to get this supported on top of the Linux kernel. This pull request is the result of that work. These changes allow us to initialise the CPUs, interrupt controller, and timers via ACPI tables, with memory information and cmdline coming from EFI. We don't support a hybrid ACPI/FDT scheme. Of course, there is still plenty of work to do (a serial console would be nice!) but I expect that to happen on a per-driver basis after this core series has been merged. Anyway, the diff stat here is fairly horrible, but splitting this up and merging it via all the different subsystems would have been extremely painful. Instead, we've got all the relevant Acks in place and I've not seen anything other than trivial (Kconfig) conflicts in -next (for completeness, I've included my resolution below). Nearly half of the insertions fall under Documentation/. So, we'll see how this goes. Right now, it all depends on EXPERT and I fully expect people to use FDT by default for the immediate future" * tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (31 commits) ARM64 / ACPI: make acpi_map_gic_cpu_interface() as void function ARM64 / ACPI: Ignore the return error value of acpi_map_gic_cpu_interface() ARM64 / ACPI: fix usage of acpi_map_gic_cpu_interface ARM64: kernel: acpi: honour acpi=force command line parameter ARM64: kernel: acpi: refactor ACPI tables init and checks ARM64: kernel: psci: let ACPI probe PSCI version ARM64: kernel: psci: factor out probe function ACPI: move arm64 GSI IRQ model to generic GSI IRQ layer ARM64 / ACPI: Don't unflatten device tree if acpi=force is passed ARM64 / ACPI: additions of ACPI documentation for arm64 Documentation: ACPI for ARM64 ARM64 / ACPI: Enable ARM64 in Kconfig XEN / ACPI: Make XEN ACPI depend on X86 ARM64 / ACPI: Select ACPI_REDUCED_HARDWARE_ONLY if ACPI is enabled on ARM64 clocksource / arch_timer: Parse GTDT to initialize arch timer irqchip: Add GICv2 specific ACPI boot support ARM64 / ACPI: Introduce ACPI_IRQ_MODEL_GIC and register device's gsi ACPI / processor: Make it possible to get CPU hardware ID via GICC ACPI / processor: Introduce phys_cpuid_t for CPU hardware ID ARM64 / ACPI: Parse MADT for SMP initialization ...
Diffstat (limited to 'arch/arm64')
-rw-r--r--arch/arm64/Kconfig4
-rw-r--r--arch/arm64/include/asm/acenv.h18
-rw-r--r--arch/arm64/include/asm/acpi.h96
-rw-r--r--arch/arm64/include/asm/cpu_ops.h1
-rw-r--r--arch/arm64/include/asm/fixmap.h3
-rw-r--r--arch/arm64/include/asm/irq.h13
-rw-r--r--arch/arm64/include/asm/pci.h6
-rw-r--r--arch/arm64/include/asm/psci.h3
-rw-r--r--arch/arm64/include/asm/smp.h5
-rw-r--r--arch/arm64/kernel/Makefile1
-rw-r--r--arch/arm64/kernel/acpi.c345
-rw-r--r--arch/arm64/kernel/cpu_ops.c2
-rw-r--r--arch/arm64/kernel/pci.c25
-rw-r--r--arch/arm64/kernel/psci.c112
-rw-r--r--arch/arm64/kernel/setup.c21
-rw-r--r--arch/arm64/kernel/smp.c2
-rw-r--r--arch/arm64/kernel/time.c7
17 files changed, 621 insertions, 43 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index da5f20e8cc50..4269dba63cf1 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1,5 +1,7 @@
1config ARM64 1config ARM64
2 def_bool y 2 def_bool y
3 select ACPI_GENERIC_GSI if ACPI
4 select ACPI_REDUCED_HARDWARE_ONLY if ACPI
3 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE 5 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
4 select ARCH_HAS_ELF_RANDOMIZE 6 select ARCH_HAS_ELF_RANDOMIZE
5 select ARCH_HAS_GCOV_PROFILE_ALL 7 select ARCH_HAS_GCOV_PROFILE_ALL
@@ -758,6 +760,8 @@ source "drivers/Kconfig"
758 760
759source "drivers/firmware/Kconfig" 761source "drivers/firmware/Kconfig"
760 762
763source "drivers/acpi/Kconfig"
764
761source "fs/Kconfig" 765source "fs/Kconfig"
762 766
763source "arch/arm64/kvm/Kconfig" 767source "arch/arm64/kvm/Kconfig"
diff --git a/arch/arm64/include/asm/acenv.h b/arch/arm64/include/asm/acenv.h
new file mode 100644
index 000000000000..b49166fde7ea
--- /dev/null
+++ b/arch/arm64/include/asm/acenv.h
@@ -0,0 +1,18 @@
1/*
2 * ARM64 specific ACPICA environments and implementation
3 *
4 * Copyright (C) 2014, Linaro Ltd.
5 * Author: Hanjun Guo <hanjun.guo@linaro.org>
6 * Author: Graeme Gregory <graeme.gregory@linaro.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef _ASM_ACENV_H
14#define _ASM_ACENV_H
15
16/* It is required unconditionally by ACPI core, update it when needed. */
17
18#endif /* _ASM_ACENV_H */
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
new file mode 100644
index 000000000000..59c05d8ea4a0
--- /dev/null
+++ b/arch/arm64/include/asm/acpi.h
@@ -0,0 +1,96 @@
1/*
2 * Copyright (C) 2013-2014, Linaro Ltd.
3 * Author: Al Stone <al.stone@linaro.org>
4 * Author: Graeme Gregory <graeme.gregory@linaro.org>
5 * Author: Hanjun Guo <hanjun.guo@linaro.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation;
10 */
11
12#ifndef _ASM_ACPI_H
13#define _ASM_ACPI_H
14
15#include <linux/mm.h>
16#include <linux/irqchip/arm-gic-acpi.h>
17
18#include <asm/cputype.h>
19#include <asm/smp_plat.h>
20
21/* Basic configuration for ACPI */
22#ifdef CONFIG_ACPI
23/* ACPI table mapping after acpi_gbl_permanent_mmap is set */
24static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
25 acpi_size size)
26{
27 if (!page_is_ram(phys >> PAGE_SHIFT))
28 return ioremap(phys, size);
29
30 return ioremap_cache(phys, size);
31}
32#define acpi_os_ioremap acpi_os_ioremap
33
34typedef u64 phys_cpuid_t;
35#define PHYS_CPUID_INVALID INVALID_HWID
36
37#define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */
38extern int acpi_disabled;
39extern int acpi_noirq;
40extern int acpi_pci_disabled;
41
42/* 1 to indicate PSCI 0.2+ is implemented */
43static inline bool acpi_psci_present(void)
44{
45 return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;
46}
47
48/* 1 to indicate HVC must be used instead of SMC as the PSCI conduit */
49static inline bool acpi_psci_use_hvc(void)
50{
51 return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC;
52}
53
54static inline void disable_acpi(void)
55{
56 acpi_disabled = 1;
57 acpi_pci_disabled = 1;
58 acpi_noirq = 1;
59}
60
61static inline void enable_acpi(void)
62{
63 acpi_disabled = 0;
64 acpi_pci_disabled = 0;
65 acpi_noirq = 0;
66}
67
68/*
69 * The ACPI processor driver for ACPI core code needs this macro
70 * to find out this cpu was already mapped (mapping from CPU hardware
71 * ID to CPU logical ID) or not.
72 */
73#define cpu_physical_id(cpu) cpu_logical_map(cpu)
74
75/*
76 * It's used from ACPI core in kdump to boot UP system with SMP kernel,
77 * with this check the ACPI core will not override the CPU index
78 * obtained from GICC with 0 and not print some error message as well.
79 * Since MADT must provide at least one GICC structure for GIC
80 * initialization, CPU will be always available in MADT on ARM64.
81 */
82static inline bool acpi_has_cpu_in_madt(void)
83{
84 return true;
85}
86
87static inline void arch_fix_phys_package_id(int num, u32 slot) { }
88void __init acpi_init_cpus(void);
89
90#else
91static inline bool acpi_psci_present(void) { return false; }
92static inline bool acpi_psci_use_hvc(void) { return false; }
93static inline void acpi_init_cpus(void) { }
94#endif /* CONFIG_ACPI */
95
96#endif /*_ASM_ACPI_H*/
diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h
index da301ee7395c..5a31d6716914 100644
--- a/arch/arm64/include/asm/cpu_ops.h
+++ b/arch/arm64/include/asm/cpu_ops.h
@@ -66,5 +66,6 @@ struct cpu_operations {
66extern const struct cpu_operations *cpu_ops[NR_CPUS]; 66extern const struct cpu_operations *cpu_ops[NR_CPUS];
67int __init cpu_read_ops(struct device_node *dn, int cpu); 67int __init cpu_read_ops(struct device_node *dn, int cpu);
68void __init cpu_read_bootcpu_ops(void); 68void __init cpu_read_bootcpu_ops(void);
69const struct cpu_operations *cpu_get_ops(const char *name);
69 70
70#endif /* ifndef __ASM_CPU_OPS_H */ 71#endif /* ifndef __ASM_CPU_OPS_H */
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 926495686554..95e6b6dcbe37 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -62,6 +62,9 @@ void __init early_fixmap_init(void);
62 62
63#define __early_set_fixmap __set_fixmap 63#define __early_set_fixmap __set_fixmap
64 64
65#define __late_set_fixmap __set_fixmap
66#define __late_clear_fixmap(idx) __set_fixmap((idx), 0, FIXMAP_PAGE_CLEAR)
67
65extern void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot); 68extern void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
66 69
67#include <asm-generic/fixmap.h> 70#include <asm-generic/fixmap.h>
diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h
index 94c53674a31d..bbb251b14746 100644
--- a/arch/arm64/include/asm/irq.h
+++ b/arch/arm64/include/asm/irq.h
@@ -1,6 +1,8 @@
1#ifndef __ASM_IRQ_H 1#ifndef __ASM_IRQ_H
2#define __ASM_IRQ_H 2#define __ASM_IRQ_H
3 3
4#include <linux/irqchip/arm-gic-acpi.h>
5
4#include <asm-generic/irq.h> 6#include <asm-generic/irq.h>
5 7
6struct pt_regs; 8struct pt_regs;
@@ -8,4 +10,15 @@ struct pt_regs;
8extern void migrate_irqs(void); 10extern void migrate_irqs(void);
9extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); 11extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
10 12
13static inline void acpi_irq_init(void)
14{
15 /*
16 * Hardcode ACPI IRQ chip initialization to GICv2 for now.
17 * Proper irqchip infrastructure will be implemented along with
18 * incoming GICv2m|GICv3|ITS bits.
19 */
20 acpi_gic_init();
21}
22#define acpi_irq_init acpi_irq_init
23
11#endif 24#endif
diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
index 872ba939fcb2..b008a72f8bc0 100644
--- a/arch/arm64/include/asm/pci.h
+++ b/arch/arm64/include/asm/pci.h
@@ -27,6 +27,12 @@
27extern int isa_dma_bridge_buggy; 27extern int isa_dma_bridge_buggy;
28 28
29#ifdef CONFIG_PCI 29#ifdef CONFIG_PCI
30static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
31{
32 /* no legacy IRQ on arm64 */
33 return -ENODEV;
34}
35
30static inline int pci_proc_domain(struct pci_bus *bus) 36static inline int pci_proc_domain(struct pci_bus *bus)
31{ 37{
32 return 1; 38 return 1;
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h
index e5312ea0ec1a..2454bc59c916 100644
--- a/arch/arm64/include/asm/psci.h
+++ b/arch/arm64/include/asm/psci.h
@@ -14,6 +14,7 @@
14#ifndef __ASM_PSCI_H 14#ifndef __ASM_PSCI_H
15#define __ASM_PSCI_H 15#define __ASM_PSCI_H
16 16
17int psci_init(void); 17int psci_dt_init(void);
18int psci_acpi_init(void);
18 19
19#endif /* __ASM_PSCI_H */ 20#endif /* __ASM_PSCI_H */
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index 780f82c827b6..bf22650b1a78 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -39,9 +39,10 @@ extern void show_ipi_list(struct seq_file *p, int prec);
39extern void handle_IPI(int ipinr, struct pt_regs *regs); 39extern void handle_IPI(int ipinr, struct pt_regs *regs);
40 40
41/* 41/*
42 * Setup the set of possible CPUs (via set_cpu_possible) 42 * Discover the set of possible CPUs and determine their
43 * SMP operations.
43 */ 44 */
44extern void smp_init_cpus(void); 45extern void of_smp_init_cpus(void);
45 46
46/* 47/*
47 * Provide a function to raise an IPI cross call on CPUs in callmap. 48 * Provide a function to raise an IPI cross call on CPUs in callmap.
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index b12e15b80516..426d0763c81b 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -35,6 +35,7 @@ arm64-obj-$(CONFIG_KGDB) += kgdb.o
35arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o 35arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
36arm64-obj-$(CONFIG_PCI) += pci.o 36arm64-obj-$(CONFIG_PCI) += pci.o
37arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o 37arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
38arm64-obj-$(CONFIG_ACPI) += acpi.o
38 39
39obj-y += $(arm64-obj-y) vdso/ 40obj-y += $(arm64-obj-y) vdso/
40obj-m += $(arm64-obj-m) 41obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
new file mode 100644
index 000000000000..8b839558838e
--- /dev/null
+++ b/arch/arm64/kernel/acpi.c
@@ -0,0 +1,345 @@
1/*
2 * ARM64 Specific Low-Level ACPI Boot Support
3 *
4 * Copyright (C) 2013-2014, Linaro Ltd.
5 * Author: Al Stone <al.stone@linaro.org>
6 * Author: Graeme Gregory <graeme.gregory@linaro.org>
7 * Author: Hanjun Guo <hanjun.guo@linaro.org>
8 * Author: Tomasz Nowicki <tomasz.nowicki@linaro.org>
9 * Author: Naresh Bhat <naresh.bhat@linaro.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
16#define pr_fmt(fmt) "ACPI: " fmt
17
18#include <linux/acpi.h>
19#include <linux/bootmem.h>
20#include <linux/cpumask.h>
21#include <linux/init.h>
22#include <linux/irq.h>
23#include <linux/irqdomain.h>
24#include <linux/memblock.h>
25#include <linux/of_fdt.h>
26#include <linux/smp.h>
27
28#include <asm/cputype.h>
29#include <asm/cpu_ops.h>
30#include <asm/smp_plat.h>
31
32int acpi_noirq = 1; /* skip ACPI IRQ initialization */
33int acpi_disabled = 1;
34EXPORT_SYMBOL(acpi_disabled);
35
36int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */
37EXPORT_SYMBOL(acpi_pci_disabled);
38
39/* Processors with enabled flag and sane MPIDR */
40static int enabled_cpus;
41
42/* Boot CPU is valid or not in MADT */
43static bool bootcpu_valid __initdata;
44
45static bool param_acpi_off __initdata;
46static bool param_acpi_force __initdata;
47
48static int __init parse_acpi(char *arg)
49{
50 if (!arg)
51 return -EINVAL;
52
53 /* "acpi=off" disables both ACPI table parsing and interpreter */
54 if (strcmp(arg, "off") == 0)
55 param_acpi_off = true;
56 else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
57 param_acpi_force = true;
58 else
59 return -EINVAL; /* Core will print when we return error */
60
61 return 0;
62}
63early_param("acpi", parse_acpi);
64
65static int __init dt_scan_depth1_nodes(unsigned long node,
66 const char *uname, int depth,
67 void *data)
68{
69 /*
70 * Return 1 as soon as we encounter a node at depth 1 that is
71 * not the /chosen node.
72 */
73 if (depth == 1 && (strcmp(uname, "chosen") != 0))
74 return 1;
75 return 0;
76}
77
78/*
79 * __acpi_map_table() will be called before page_init(), so early_ioremap()
80 * or early_memremap() should be called here to for ACPI table mapping.
81 */
82char *__init __acpi_map_table(unsigned long phys, unsigned long size)
83{
84 if (!size)
85 return NULL;
86
87 return early_memremap(phys, size);
88}
89
90void __init __acpi_unmap_table(char *map, unsigned long size)
91{
92 if (!map || !size)
93 return;
94
95 early_memunmap(map, size);
96}
97
98/**
99 * acpi_map_gic_cpu_interface - generates a logical cpu number
100 * and map to MPIDR represented by GICC structure
101 */
102static void __init
103acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
104{
105 int i;
106 u64 mpidr = processor->arm_mpidr & MPIDR_HWID_BITMASK;
107 bool enabled = !!(processor->flags & ACPI_MADT_ENABLED);
108
109 if (mpidr == INVALID_HWID) {
110 pr_info("Skip MADT cpu entry with invalid MPIDR\n");
111 return;
112 }
113
114 total_cpus++;
115 if (!enabled)
116 return;
117
118 if (enabled_cpus >= NR_CPUS) {
119 pr_warn("NR_CPUS limit of %d reached, Processor %d/0x%llx ignored.\n",
120 NR_CPUS, total_cpus, mpidr);
121 return;
122 }
123
124 /* Check if GICC structure of boot CPU is available in the MADT */
125 if (cpu_logical_map(0) == mpidr) {
126 if (bootcpu_valid) {
127 pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
128 mpidr);
129 return;
130 }
131
132 bootcpu_valid = true;
133 }
134
135 /*
136 * Duplicate MPIDRs are a recipe for disaster. Scan
137 * all initialized entries and check for
138 * duplicates. If any is found just ignore the CPU.
139 */
140 for (i = 1; i < enabled_cpus; i++) {
141 if (cpu_logical_map(i) == mpidr) {
142 pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
143 mpidr);
144 return;
145 }
146 }
147
148 if (!acpi_psci_present())
149 return;
150
151 cpu_ops[enabled_cpus] = cpu_get_ops("psci");
152 /* CPU 0 was already initialized */
153 if (enabled_cpus) {
154 if (!cpu_ops[enabled_cpus])
155 return;
156
157 if (cpu_ops[enabled_cpus]->cpu_init(NULL, enabled_cpus))
158 return;
159
160 /* map the logical cpu id to cpu MPIDR */
161 cpu_logical_map(enabled_cpus) = mpidr;
162 }
163
164 enabled_cpus++;
165}
166
167static int __init
168acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
169 const unsigned long end)
170{
171 struct acpi_madt_generic_interrupt *processor;
172
173 processor = (struct acpi_madt_generic_interrupt *)header;
174
175 if (BAD_MADT_ENTRY(processor, end))
176 return -EINVAL;
177
178 acpi_table_print_madt_entry(header);
179 acpi_map_gic_cpu_interface(processor);
180 return 0;
181}
182
183/* Parse GIC cpu interface entries in MADT for SMP init */
184void __init acpi_init_cpus(void)
185{
186 int count, i;
187
188 /*
189 * do a partial walk of MADT to determine how many CPUs
190 * we have including disabled CPUs, and get information
191 * we need for SMP init
192 */
193 count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
194 acpi_parse_gic_cpu_interface, 0);
195
196 if (!count) {
197 pr_err("No GIC CPU interface entries present\n");
198 return;
199 } else if (count < 0) {
200 pr_err("Error parsing GIC CPU interface entry\n");
201 return;
202 }
203
204 if (!bootcpu_valid) {
205 pr_err("MADT missing boot CPU MPIDR, not enabling secondaries\n");
206 return;
207 }
208
209 for (i = 0; i < enabled_cpus; i++)
210 set_cpu_possible(i, true);
211
212 /* Make boot-up look pretty */
213 pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus);
214}
215
216/*
217 * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity
218 * checks on it
219 *
220 * Return 0 on success, <0 on failure
221 */
222static int __init acpi_fadt_sanity_check(void)
223{
224 struct acpi_table_header *table;
225 struct acpi_table_fadt *fadt;
226 acpi_status status;
227 acpi_size tbl_size;
228 int ret = 0;
229
230 /*
231 * FADT is required on arm64; retrieve it to check its presence
232 * and carry out revision and ACPI HW reduced compliancy tests
233 */
234 status = acpi_get_table_with_size(ACPI_SIG_FADT, 0, &table, &tbl_size);
235 if (ACPI_FAILURE(status)) {
236 const char *msg = acpi_format_exception(status);
237
238 pr_err("Failed to get FADT table, %s\n", msg);
239 return -ENODEV;
240 }
241
242 fadt = (struct acpi_table_fadt *)table;
243
244 /*
245 * Revision in table header is the FADT Major revision, and there
246 * is a minor revision of FADT which was introduced by ACPI 5.1,
247 * we only deal with ACPI 5.1 or newer revision to get GIC and SMP
248 * boot protocol configuration data.
249 */
250 if (table->revision < 5 ||
251 (table->revision == 5 && fadt->minor_revision < 1)) {
252 pr_err("Unsupported FADT revision %d.%d, should be 5.1+\n",
253 table->revision, fadt->minor_revision);
254 ret = -EINVAL;
255 goto out;
256 }
257
258 if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) {
259 pr_err("FADT not ACPI hardware reduced compliant\n");
260 ret = -EINVAL;
261 }
262
263out:
264 /*
265 * acpi_get_table_with_size() creates FADT table mapping that
266 * should be released after parsing and before resuming boot
267 */
268 early_acpi_os_unmap_memory(table, tbl_size);
269 return ret;
270}
271
272/*
273 * acpi_boot_table_init() called from setup_arch(), always.
274 * 1. find RSDP and get its address, and then find XSDT
275 * 2. extract all tables and checksums them all
276 * 3. check ACPI FADT revision
277 * 4. check ACPI FADT HW reduced flag
278 *
279 * We can parse ACPI boot-time tables such as MADT after
280 * this function is called.
281 *
282 * On return ACPI is enabled if either:
283 *
284 * - ACPI tables are initialized and sanity checks passed
285 * - acpi=force was passed in the command line and ACPI was not disabled
286 * explicitly through acpi=off command line parameter
287 *
288 * ACPI is disabled on function return otherwise
289 */
290void __init acpi_boot_table_init(void)
291{
292 /*
293 * Enable ACPI instead of device tree unless
294 * - ACPI has been disabled explicitly (acpi=off), or
295 * - the device tree is not empty (it has more than just a /chosen node)
296 * and ACPI has not been force enabled (acpi=force)
297 */
298 if (param_acpi_off ||
299 (!param_acpi_force && of_scan_flat_dt(dt_scan_depth1_nodes, NULL)))
300 return;
301
302 /*
303 * ACPI is disabled at this point. Enable it in order to parse
304 * the ACPI tables and carry out sanity checks
305 */
306 enable_acpi();
307
308 /*
309 * If ACPI tables are initialized and FADT sanity checks passed,
310 * leave ACPI enabled and carry on booting; otherwise disable ACPI
311 * on initialization error.
312 * If acpi=force was passed on the command line it forces ACPI
313 * to be enabled even if its initialization failed.
314 */
315 if (acpi_table_init() || acpi_fadt_sanity_check()) {
316 pr_err("Failed to init ACPI tables\n");
317 if (!param_acpi_force)
318 disable_acpi();
319 }
320}
321
322void __init acpi_gic_init(void)
323{
324 struct acpi_table_header *table;
325 acpi_status status;
326 acpi_size tbl_size;
327 int err;
328
329 if (acpi_disabled)
330 return;
331
332 status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size);
333 if (ACPI_FAILURE(status)) {
334 const char *msg = acpi_format_exception(status);
335
336 pr_err("Failed to get MADT table, %s\n", msg);
337 return;
338 }
339
340 err = gic_v2_acpi_init(table);
341 if (err)
342 pr_err("Failed to initialize GIC IRQ controller");
343
344 early_acpi_os_unmap_memory((char *)table, tbl_size);
345}
diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c
index cce952440c64..fb8ff9ba467a 100644
--- a/arch/arm64/kernel/cpu_ops.c
+++ b/arch/arm64/kernel/cpu_ops.c
@@ -35,7 +35,7 @@ static const struct cpu_operations *supported_cpu_ops[] __initconst = {
35 NULL, 35 NULL,
36}; 36};
37 37
38static const struct cpu_operations * __init cpu_get_ops(const char *name) 38const struct cpu_operations * __init cpu_get_ops(const char *name)
39{ 39{
40 const struct cpu_operations **ops = supported_cpu_ops; 40 const struct cpu_operations **ops = supported_cpu_ops;
41 41
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index 6f93c24ca801..4095379dc069 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -10,6 +10,7 @@
10 * 10 *
11 */ 11 */
12 12
13#include <linux/acpi.h>
13#include <linux/init.h> 14#include <linux/init.h>
14#include <linux/io.h> 15#include <linux/io.h>
15#include <linux/kernel.h> 16#include <linux/kernel.h>
@@ -46,3 +47,27 @@ int pcibios_add_device(struct pci_dev *dev)
46 47
47 return 0; 48 return 0;
48} 49}
50
51/*
52 * raw_pci_read/write - Platform-specific PCI config space access.
53 */
54int raw_pci_read(unsigned int domain, unsigned int bus,
55 unsigned int devfn, int reg, int len, u32 *val)
56{
57 return -ENXIO;
58}
59
60int raw_pci_write(unsigned int domain, unsigned int bus,
61 unsigned int devfn, int reg, int len, u32 val)
62{
63 return -ENXIO;
64}
65
66#ifdef CONFIG_ACPI
67/* Root bridge scanning */
68struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
69{
70 /* TODO: Should be revisited when implementing PCI on ACPI */
71 return NULL;
72}
73#endif
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index 9b8a70ae64a1..ea18cb53921e 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -15,6 +15,7 @@
15 15
16#define pr_fmt(fmt) "psci: " fmt 16#define pr_fmt(fmt) "psci: " fmt
17 17
18#include <linux/acpi.h>
18#include <linux/init.h> 19#include <linux/init.h>
19#include <linux/of.h> 20#include <linux/of.h>
20#include <linux/smp.h> 21#include <linux/smp.h>
@@ -24,6 +25,7 @@
24#include <linux/slab.h> 25#include <linux/slab.h>
25#include <uapi/linux/psci.h> 26#include <uapi/linux/psci.h>
26 27
28#include <asm/acpi.h>
27#include <asm/compiler.h> 29#include <asm/compiler.h>
28#include <asm/cpu_ops.h> 30#include <asm/cpu_ops.h>
29#include <asm/errno.h> 31#include <asm/errno.h>
@@ -273,39 +275,8 @@ static void psci_sys_poweroff(void)
273 invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); 275 invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
274} 276}
275 277
276/* 278static void __init psci_0_2_set_functions(void)
277 * PSCI Function IDs for v0.2+ are well defined so use
278 * standard values.
279 */
280static int __init psci_0_2_init(struct device_node *np)
281{ 279{
282 int err, ver;
283
284 err = get_set_conduit_method(np);
285
286 if (err)
287 goto out_put_node;
288
289 ver = psci_get_version();
290
291 if (ver == PSCI_RET_NOT_SUPPORTED) {
292 /* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */
293 pr_err("PSCI firmware does not comply with the v0.2 spec.\n");
294 err = -EOPNOTSUPP;
295 goto out_put_node;
296 } else {
297 pr_info("PSCIv%d.%d detected in firmware.\n",
298 PSCI_VERSION_MAJOR(ver),
299 PSCI_VERSION_MINOR(ver));
300
301 if (PSCI_VERSION_MAJOR(ver) == 0 &&
302 PSCI_VERSION_MINOR(ver) < 2) {
303 err = -EINVAL;
304 pr_err("Conflicting PSCI version detected.\n");
305 goto out_put_node;
306 }
307 }
308
309 pr_info("Using standard PSCI v0.2 function IDs\n"); 280 pr_info("Using standard PSCI v0.2 function IDs\n");
310 psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; 281 psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND;
311 psci_ops.cpu_suspend = psci_cpu_suspend; 282 psci_ops.cpu_suspend = psci_cpu_suspend;
@@ -329,6 +300,60 @@ static int __init psci_0_2_init(struct device_node *np)
329 arm_pm_restart = psci_sys_reset; 300 arm_pm_restart = psci_sys_reset;
330 301
331 pm_power_off = psci_sys_poweroff; 302 pm_power_off = psci_sys_poweroff;
303}
304
305/*
306 * Probe function for PSCI firmware versions >= 0.2
307 */
308static int __init psci_probe(void)
309{
310 int ver = psci_get_version();
311
312 if (ver == PSCI_RET_NOT_SUPPORTED) {
313 /*
314 * PSCI versions >=0.2 mandates implementation of
315 * PSCI_VERSION.
316 */
317 pr_err("PSCI firmware does not comply with the v0.2 spec.\n");
318 return -EOPNOTSUPP;
319 } else {
320 pr_info("PSCIv%d.%d detected in firmware.\n",
321 PSCI_VERSION_MAJOR(ver),
322 PSCI_VERSION_MINOR(ver));
323
324 if (PSCI_VERSION_MAJOR(ver) == 0 &&
325 PSCI_VERSION_MINOR(ver) < 2) {
326 pr_err("Conflicting PSCI version detected.\n");
327 return -EINVAL;
328 }
329 }
330
331 psci_0_2_set_functions();
332
333 return 0;
334}
335
336/*
337 * PSCI init function for PSCI versions >=0.2
338 *
339 * Probe based on PSCI PSCI_VERSION function
340 */
341static int __init psci_0_2_init(struct device_node *np)
342{
343 int err;
344
345 err = get_set_conduit_method(np);
346
347 if (err)
348 goto out_put_node;
349 /*
350 * Starting with v0.2, the PSCI specification introduced a call
351 * (PSCI_VERSION) that allows probing the firmware version, so
352 * that PSCI function IDs and version specific initialization
353 * can be carried out according to the specific version reported
354 * by firmware
355 */
356 err = psci_probe();
332 357
333out_put_node: 358out_put_node:
334 of_node_put(np); 359 of_node_put(np);
@@ -381,7 +406,7 @@ static const struct of_device_id psci_of_match[] __initconst = {
381 {}, 406 {},
382}; 407};
383 408
384int __init psci_init(void) 409int __init psci_dt_init(void)
385{ 410{
386 struct device_node *np; 411 struct device_node *np;
387 const struct of_device_id *matched_np; 412 const struct of_device_id *matched_np;
@@ -396,6 +421,27 @@ int __init psci_init(void)
396 return init_fn(np); 421 return init_fn(np);
397} 422}
398 423
424/*
425 * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's
426 * explicitly clarified in SBBR
427 */
428int __init psci_acpi_init(void)
429{
430 if (!acpi_psci_present()) {
431 pr_info("is not implemented in ACPI.\n");
432 return -EOPNOTSUPP;
433 }
434
435 pr_info("probing for conduit method from ACPI.\n");
436
437 if (acpi_psci_use_hvc())
438 invoke_psci_fn = __invoke_psci_fn_hvc;
439 else
440 invoke_psci_fn = __invoke_psci_fn_smc;
441
442 return psci_probe();
443}
444
399#ifdef CONFIG_SMP 445#ifdef CONFIG_SMP
400 446
401static int __init cpu_psci_cpu_init(struct device_node *dn, unsigned int cpu) 447static int __init cpu_psci_cpu_init(struct device_node *dn, unsigned int cpu)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 51ef97274b52..74753132c3ac 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -17,6 +17,7 @@
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */ 18 */
19 19
20#include <linux/acpi.h>
20#include <linux/export.h> 21#include <linux/export.h>
21#include <linux/kernel.h> 22#include <linux/kernel.h>
22#include <linux/stddef.h> 23#include <linux/stddef.h>
@@ -46,6 +47,7 @@
46#include <linux/efi.h> 47#include <linux/efi.h>
47#include <linux/personality.h> 48#include <linux/personality.h>
48 49
50#include <asm/acpi.h>
49#include <asm/fixmap.h> 51#include <asm/fixmap.h>
50#include <asm/cpu.h> 52#include <asm/cpu.h>
51#include <asm/cputype.h> 53#include <asm/cputype.h>
@@ -395,18 +397,27 @@ void __init setup_arch(char **cmdline_p)
395 efi_init(); 397 efi_init();
396 arm64_memblock_init(); 398 arm64_memblock_init();
397 399
400 /* Parse the ACPI tables for possible boot-time configuration */
401 acpi_boot_table_init();
402
398 paging_init(); 403 paging_init();
399 request_standard_resources(); 404 request_standard_resources();
400 405
401 early_ioremap_reset(); 406 early_ioremap_reset();
402 407
403 unflatten_device_tree(); 408 if (acpi_disabled) {
404 409 unflatten_device_tree();
405 psci_init(); 410 psci_dt_init();
411 cpu_read_bootcpu_ops();
412#ifdef CONFIG_SMP
413 of_smp_init_cpus();
414#endif
415 } else {
416 psci_acpi_init();
417 acpi_init_cpus();
418 }
406 419
407 cpu_read_bootcpu_ops();
408#ifdef CONFIG_SMP 420#ifdef CONFIG_SMP
409 smp_init_cpus();
410 smp_build_mpidr_hash(); 421 smp_build_mpidr_hash();
411#endif 422#endif
412 423
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 714411f62391..2cb008177252 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -323,7 +323,7 @@ void __init smp_prepare_boot_cpu(void)
323 * cpu logical map array containing MPIDR values related to logical 323 * cpu logical map array containing MPIDR values related to logical
324 * cpus. Assumes that cpu_logical_map(0) has already been initialized. 324 * cpus. Assumes that cpu_logical_map(0) has already been initialized.
325 */ 325 */
326void __init smp_init_cpus(void) 326void __init of_smp_init_cpus(void)
327{ 327{
328 struct device_node *dn = NULL; 328 struct device_node *dn = NULL;
329 unsigned int i, cpu = 1; 329 unsigned int i, cpu = 1;
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c
index 1a7125c3099b..42f9195cf2f8 100644
--- a/arch/arm64/kernel/time.c
+++ b/arch/arm64/kernel/time.c
@@ -35,6 +35,7 @@
35#include <linux/delay.h> 35#include <linux/delay.h>
36#include <linux/clocksource.h> 36#include <linux/clocksource.h>
37#include <linux/clk-provider.h> 37#include <linux/clk-provider.h>
38#include <linux/acpi.h>
38 39
39#include <clocksource/arm_arch_timer.h> 40#include <clocksource/arm_arch_timer.h>
40 41
@@ -72,6 +73,12 @@ void __init time_init(void)
72 73
73 tick_setup_hrtimer_broadcast(); 74 tick_setup_hrtimer_broadcast();
74 75
76 /*
77 * Since ACPI or FDT will only one be available in the system,
78 * we can use acpi_generic_timer_init() here safely
79 */
80 acpi_generic_timer_init();
81
75 arch_timer_rate = arch_timer_get_rate(); 82 arch_timer_rate = arch_timer_get_rate();
76 if (!arch_timer_rate) 83 if (!arch_timer_rate)
77 panic("Unable to initialise architected timer.\n"); 84 panic("Unable to initialise architected timer.\n");