diff options
author | Matt Fleming <matt.fleming@intel.com> | 2013-09-05 14:55:00 -0400 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2013-09-05 14:55:00 -0400 |
commit | 9efff3899b90e5ead9e676af9736e891ee23ce41 (patch) | |
tree | 9a07ec52e822200704c8af9efea9a8971545cc98 /drivers/firmware | |
parent | 6f9dd30c22da4e48c4b7b837e9641f072e673161 (diff) | |
parent | 258f6fd738221766b512cd8c7120563b78d62829 (diff) |
Merge branch 'arm/efi-stub' into next
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/efi/efi.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 5145fa344ad5..2e2fbdec0845 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
@@ -13,11 +13,27 @@ | |||
13 | * This file is released under the GPLv2. | 13 | * This file is released under the GPLv2. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
17 | |||
16 | #include <linux/kobject.h> | 18 | #include <linux/kobject.h> |
17 | #include <linux/module.h> | 19 | #include <linux/module.h> |
18 | #include <linux/init.h> | 20 | #include <linux/init.h> |
19 | #include <linux/device.h> | 21 | #include <linux/device.h> |
20 | #include <linux/efi.h> | 22 | #include <linux/efi.h> |
23 | #include <linux/io.h> | ||
24 | |||
25 | struct efi __read_mostly efi = { | ||
26 | .mps = EFI_INVALID_TABLE_ADDR, | ||
27 | .acpi = EFI_INVALID_TABLE_ADDR, | ||
28 | .acpi20 = EFI_INVALID_TABLE_ADDR, | ||
29 | .smbios = EFI_INVALID_TABLE_ADDR, | ||
30 | .sal_systab = EFI_INVALID_TABLE_ADDR, | ||
31 | .boot_info = EFI_INVALID_TABLE_ADDR, | ||
32 | .hcdp = EFI_INVALID_TABLE_ADDR, | ||
33 | .uga = EFI_INVALID_TABLE_ADDR, | ||
34 | .uv_systab = EFI_INVALID_TABLE_ADDR, | ||
35 | }; | ||
36 | EXPORT_SYMBOL(efi); | ||
21 | 37 | ||
22 | static struct kobject *efi_kobj; | 38 | static struct kobject *efi_kobj; |
23 | static struct kobject *efivars_kobj; | 39 | static struct kobject *efivars_kobj; |
@@ -132,3 +148,127 @@ err_put: | |||
132 | } | 148 | } |
133 | 149 | ||
134 | subsys_initcall(efisubsys_init); | 150 | subsys_initcall(efisubsys_init); |
151 | |||
152 | |||
153 | /* | ||
154 | * We can't ioremap data in EFI boot services RAM, because we've already mapped | ||
155 | * it as RAM. So, look it up in the existing EFI memory map instead. Only | ||
156 | * callable after efi_enter_virtual_mode and before efi_free_boot_services. | ||
157 | */ | ||
158 | void __iomem *efi_lookup_mapped_addr(u64 phys_addr) | ||
159 | { | ||
160 | struct efi_memory_map *map; | ||
161 | void *p; | ||
162 | map = efi.memmap; | ||
163 | if (!map) | ||
164 | return NULL; | ||
165 | if (WARN_ON(!map->map)) | ||
166 | return NULL; | ||
167 | for (p = map->map; p < map->map_end; p += map->desc_size) { | ||
168 | efi_memory_desc_t *md = p; | ||
169 | u64 size = md->num_pages << EFI_PAGE_SHIFT; | ||
170 | u64 end = md->phys_addr + size; | ||
171 | if (!(md->attribute & EFI_MEMORY_RUNTIME) && | ||
172 | md->type != EFI_BOOT_SERVICES_CODE && | ||
173 | md->type != EFI_BOOT_SERVICES_DATA) | ||
174 | continue; | ||
175 | if (!md->virt_addr) | ||
176 | continue; | ||
177 | if (phys_addr >= md->phys_addr && phys_addr < end) { | ||
178 | phys_addr += md->virt_addr - md->phys_addr; | ||
179 | return (__force void __iomem *)(unsigned long)phys_addr; | ||
180 | } | ||
181 | } | ||
182 | return NULL; | ||
183 | } | ||
184 | |||
185 | static __initdata efi_config_table_type_t common_tables[] = { | ||
186 | {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20}, | ||
187 | {ACPI_TABLE_GUID, "ACPI", &efi.acpi}, | ||
188 | {HCDP_TABLE_GUID, "HCDP", &efi.hcdp}, | ||
189 | {MPS_TABLE_GUID, "MPS", &efi.mps}, | ||
190 | {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab}, | ||
191 | {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios}, | ||
192 | {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga}, | ||
193 | {NULL_GUID, NULL, 0}, | ||
194 | }; | ||
195 | |||
196 | static __init int match_config_table(efi_guid_t *guid, | ||
197 | unsigned long table, | ||
198 | efi_config_table_type_t *table_types) | ||
199 | { | ||
200 | u8 str[EFI_VARIABLE_GUID_LEN + 1]; | ||
201 | int i; | ||
202 | |||
203 | if (table_types) { | ||
204 | efi_guid_unparse(guid, str); | ||
205 | |||
206 | for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) { | ||
207 | efi_guid_unparse(&table_types[i].guid, str); | ||
208 | |||
209 | if (!efi_guidcmp(*guid, table_types[i].guid)) { | ||
210 | *(table_types[i].ptr) = table; | ||
211 | pr_cont(" %s=0x%lx ", | ||
212 | table_types[i].name, table); | ||
213 | return 1; | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | int __init efi_config_init(efi_config_table_type_t *arch_tables) | ||
222 | { | ||
223 | void *config_tables, *tablep; | ||
224 | int i, sz; | ||
225 | |||
226 | if (efi_enabled(EFI_64BIT)) | ||
227 | sz = sizeof(efi_config_table_64_t); | ||
228 | else | ||
229 | sz = sizeof(efi_config_table_32_t); | ||
230 | |||
231 | /* | ||
232 | * Let's see what config tables the firmware passed to us. | ||
233 | */ | ||
234 | config_tables = early_memremap(efi.systab->tables, | ||
235 | efi.systab->nr_tables * sz); | ||
236 | if (config_tables == NULL) { | ||
237 | pr_err("Could not map Configuration table!\n"); | ||
238 | return -ENOMEM; | ||
239 | } | ||
240 | |||
241 | tablep = config_tables; | ||
242 | pr_info(""); | ||
243 | for (i = 0; i < efi.systab->nr_tables; i++) { | ||
244 | efi_guid_t guid; | ||
245 | unsigned long table; | ||
246 | |||
247 | if (efi_enabled(EFI_64BIT)) { | ||
248 | u64 table64; | ||
249 | guid = ((efi_config_table_64_t *)tablep)->guid; | ||
250 | table64 = ((efi_config_table_64_t *)tablep)->table; | ||
251 | table = table64; | ||
252 | #ifndef CONFIG_64BIT | ||
253 | if (table64 >> 32) { | ||
254 | pr_cont("\n"); | ||
255 | pr_err("Table located above 4GB, disabling EFI.\n"); | ||
256 | early_iounmap(config_tables, | ||
257 | efi.systab->nr_tables * sz); | ||
258 | return -EINVAL; | ||
259 | } | ||
260 | #endif | ||
261 | } else { | ||
262 | guid = ((efi_config_table_32_t *)tablep)->guid; | ||
263 | table = ((efi_config_table_32_t *)tablep)->table; | ||
264 | } | ||
265 | |||
266 | if (!match_config_table(&guid, table, common_tables)) | ||
267 | match_config_table(&guid, table, arch_tables); | ||
268 | |||
269 | tablep += sz; | ||
270 | } | ||
271 | pr_cont("\n"); | ||
272 | early_iounmap(config_tables, efi.systab->nr_tables * sz); | ||
273 | return 0; | ||
274 | } | ||