Commit | Line | Data |
---|---|---|
37655163 AS |
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> | |
b10d79f7 | 25 | #include <linux/of_fdt.h> |
37655163 AS |
26 | #include <linux/smp.h> |
27 | ||
fccb9a81 HG |
28 | #include <asm/cputype.h> |
29 | #include <asm/cpu_ops.h> | |
30 | #include <asm/smp_plat.h> | |
31 | ||
89e44b51 JZZ |
32 | #ifdef CONFIG_ACPI_APEI |
33 | # include <linux/efi.h> | |
34 | # include <asm/pgtable.h> | |
35 | #endif | |
36 | ||
b10d79f7 AS |
37 | int acpi_noirq = 1; /* skip ACPI IRQ initialization */ |
38 | int acpi_disabled = 1; | |
37655163 AS |
39 | EXPORT_SYMBOL(acpi_disabled); |
40 | ||
b10d79f7 | 41 | int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */ |
37655163 AS |
42 | EXPORT_SYMBOL(acpi_pci_disabled); |
43 | ||
b10d79f7 | 44 | static bool param_acpi_off __initdata; |
fb094eb1 | 45 | static bool param_acpi_force __initdata; |
b10d79f7 AS |
46 | |
47 | static int __init parse_acpi(char *arg) | |
48 | { | |
49 | if (!arg) | |
50 | return -EINVAL; | |
51 | ||
52 | /* "acpi=off" disables both ACPI table parsing and interpreter */ | |
53 | if (strcmp(arg, "off") == 0) | |
54 | param_acpi_off = true; | |
55 | else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */ | |
56 | param_acpi_force = true; | |
57 | else | |
58 | return -EINVAL; /* Core will print when we return error */ | |
59 | ||
60 | return 0; | |
61 | } | |
62 | early_param("acpi", parse_acpi); | |
63 | ||
64 | static int __init dt_scan_depth1_nodes(unsigned long node, | |
65 | const char *uname, int depth, | |
66 | void *data) | |
67 | { | |
68 | /* | |
9981293f MR |
69 | * Ignore anything not directly under the root node; we'll |
70 | * catch its parent instead. | |
b10d79f7 | 71 | */ |
9981293f MR |
72 | if (depth != 1) |
73 | return 0; | |
2366c7fd | 74 | |
9981293f MR |
75 | if (strcmp(uname, "chosen") == 0) |
76 | return 0; | |
77 | ||
78 | if (strcmp(uname, "hypervisor") == 0 && | |
79 | of_flat_dt_is_compatible(node, "xen,xen")) | |
80 | return 0; | |
81 | ||
82 | /* | |
83 | * This node at depth 1 is neither a chosen node nor a xen node, | |
84 | * which we do not expect. | |
85 | */ | |
86 | return 1; | |
b10d79f7 AS |
87 | } |
88 | ||
37655163 AS |
89 | /* |
90 | * __acpi_map_table() will be called before page_init(), so early_ioremap() | |
91 | * or early_memremap() should be called here to for ACPI table mapping. | |
92 | */ | |
93 | char *__init __acpi_map_table(unsigned long phys, unsigned long size) | |
94 | { | |
95 | if (!size) | |
96 | return NULL; | |
97 | ||
98 | return early_memremap(phys, size); | |
99 | } | |
100 | ||
101 | void __init __acpi_unmap_table(char *map, unsigned long size) | |
102 | { | |
103 | if (!map || !size) | |
104 | return; | |
105 | ||
106 | early_memunmap(map, size); | |
107 | } | |
108 | ||
c5a13305 MR |
109 | bool __init acpi_psci_present(void) |
110 | { | |
111 | return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT; | |
112 | } | |
113 | ||
114 | /* Whether HVC must be used instead of SMC as the PSCI conduit */ | |
115 | bool __init acpi_psci_use_hvc(void) | |
116 | { | |
117 | return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC; | |
118 | } | |
119 | ||
54971e43 LP |
120 | /* |
121 | * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity | |
122 | * checks on it | |
123 | * | |
124 | * Return 0 on success, <0 on failure | |
125 | */ | |
126 | static int __init acpi_fadt_sanity_check(void) | |
37655163 | 127 | { |
54971e43 LP |
128 | struct acpi_table_header *table; |
129 | struct acpi_table_fadt *fadt; | |
130 | acpi_status status; | |
131 | acpi_size tbl_size; | |
132 | int ret = 0; | |
133 | ||
134 | /* | |
135 | * FADT is required on arm64; retrieve it to check its presence | |
136 | * and carry out revision and ACPI HW reduced compliancy tests | |
137 | */ | |
138 | status = acpi_get_table_with_size(ACPI_SIG_FADT, 0, &table, &tbl_size); | |
139 | if (ACPI_FAILURE(status)) { | |
140 | const char *msg = acpi_format_exception(status); | |
141 | ||
142 | pr_err("Failed to get FADT table, %s\n", msg); | |
143 | return -ENODEV; | |
144 | } | |
145 | ||
146 | fadt = (struct acpi_table_fadt *)table; | |
37655163 AS |
147 | |
148 | /* | |
149 | * Revision in table header is the FADT Major revision, and there | |
150 | * is a minor revision of FADT which was introduced by ACPI 5.1, | |
151 | * we only deal with ACPI 5.1 or newer revision to get GIC and SMP | |
54971e43 | 152 | * boot protocol configuration data. |
37655163 | 153 | */ |
54971e43 LP |
154 | if (table->revision < 5 || |
155 | (table->revision == 5 && fadt->minor_revision < 1)) { | |
156 | pr_err("Unsupported FADT revision %d.%d, should be 5.1+\n", | |
157 | table->revision, fadt->minor_revision); | |
158 | ret = -EINVAL; | |
159 | goto out; | |
fccb9a81 | 160 | } |
37655163 | 161 | |
54971e43 LP |
162 | if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) { |
163 | pr_err("FADT not ACPI hardware reduced compliant\n"); | |
164 | ret = -EINVAL; | |
165 | } | |
37655163 | 166 | |
54971e43 LP |
167 | out: |
168 | /* | |
169 | * acpi_get_table_with_size() creates FADT table mapping that | |
170 | * should be released after parsing and before resuming boot | |
171 | */ | |
172 | early_acpi_os_unmap_memory(table, tbl_size); | |
173 | return ret; | |
37655163 AS |
174 | } |
175 | ||
176 | /* | |
177 | * acpi_boot_table_init() called from setup_arch(), always. | |
178 | * 1. find RSDP and get its address, and then find XSDT | |
179 | * 2. extract all tables and checksums them all | |
180 | * 3. check ACPI FADT revision | |
54971e43 | 181 | * 4. check ACPI FADT HW reduced flag |
37655163 AS |
182 | * |
183 | * We can parse ACPI boot-time tables such as MADT after | |
184 | * this function is called. | |
54971e43 | 185 | * |
fb094eb1 LP |
186 | * On return ACPI is enabled if either: |
187 | * | |
188 | * - ACPI tables are initialized and sanity checks passed | |
189 | * - acpi=force was passed in the command line and ACPI was not disabled | |
190 | * explicitly through acpi=off command line parameter | |
191 | * | |
192 | * ACPI is disabled on function return otherwise | |
37655163 AS |
193 | */ |
194 | void __init acpi_boot_table_init(void) | |
195 | { | |
b10d79f7 AS |
196 | /* |
197 | * Enable ACPI instead of device tree unless | |
198 | * - ACPI has been disabled explicitly (acpi=off), or | |
2366c7fd SZ |
199 | * - the device tree is not empty (it has more than just a /chosen node, |
200 | * and a /hypervisor node when running on Xen) | |
b10d79f7 AS |
201 | * and ACPI has not been force enabled (acpi=force) |
202 | */ | |
203 | if (param_acpi_off || | |
204 | (!param_acpi_force && of_scan_flat_dt(dt_scan_depth1_nodes, NULL))) | |
37655163 AS |
205 | return; |
206 | ||
54971e43 LP |
207 | /* |
208 | * ACPI is disabled at this point. Enable it in order to parse | |
209 | * the ACPI tables and carry out sanity checks | |
210 | */ | |
b10d79f7 AS |
211 | enable_acpi(); |
212 | ||
54971e43 LP |
213 | /* |
214 | * If ACPI tables are initialized and FADT sanity checks passed, | |
215 | * leave ACPI enabled and carry on booting; otherwise disable ACPI | |
216 | * on initialization error. | |
fb094eb1 LP |
217 | * If acpi=force was passed on the command line it forces ACPI |
218 | * to be enabled even if its initialization failed. | |
54971e43 LP |
219 | */ |
220 | if (acpi_table_init() || acpi_fadt_sanity_check()) { | |
221 | pr_err("Failed to init ACPI tables\n"); | |
fb094eb1 LP |
222 | if (!param_acpi_force) |
223 | disable_acpi(); | |
37655163 AS |
224 | } |
225 | } | |
d60fc389 | 226 | |
89e44b51 JZZ |
227 | #ifdef CONFIG_ACPI_APEI |
228 | pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr) | |
229 | { | |
230 | /* | |
231 | * According to "Table 8 Map: EFI memory types to AArch64 memory | |
232 | * types" of UEFI 2.5 section 2.3.6.1, each EFI memory type is | |
233 | * mapped to a corresponding MAIR attribute encoding. | |
234 | * The EFI memory attribute advises all possible capabilities | |
235 | * of a memory region. We use the most efficient capability. | |
236 | */ | |
237 | ||
238 | u64 attr; | |
239 | ||
240 | attr = efi_mem_attributes(addr); | |
241 | if (attr & EFI_MEMORY_WB) | |
242 | return PAGE_KERNEL; | |
243 | if (attr & EFI_MEMORY_WT) | |
244 | return __pgprot(PROT_NORMAL_WT); | |
245 | if (attr & EFI_MEMORY_WC) | |
246 | return __pgprot(PROT_NORMAL_NC); | |
247 | return __pgprot(PROT_DEVICE_nGnRnE); | |
248 | } | |
249 | #endif |