efi: add helper function to get UEFI params from FDT
authorMark Salter <msalter@redhat.com>
Mon, 30 Dec 2013 17:12:12 +0000 (12:12 -0500)
committerMark Brown <broonie@linaro.org>
Mon, 16 Jun 2014 20:35:23 +0000 (21:35 +0100)
ARM and ARM64 architectures use the device tree to pass UEFI parameters
from stub to kernel. These parameters are things known to the stub but
not discoverable by the kernel after the stub calls ExitBootSerives().
There is a helper function in:

   drivers/firmware/efi/fdt.c

which the stub uses to add the UEFI parameters to the device tree.
This patch adds a complimentary helper function which UEFI runtime
support may use to retrieve the parameters from the device tree.
If an architecture wants to use this helper, it should select
CONFIG_EFI_PARAMS_FROM_FDT.

Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
(cherry picked from commit 0302f71c0aa59571ac306f93068fbbfe65ea349b)
Signed-off-by: Mark Brown <broonie@linaro.org>
Conflicts:
drivers/firmware/efi/Kconfig

drivers/firmware/efi/Kconfig
drivers/firmware/efi/efi.c
include/linux/efi.h

index b0fc7c79dfbb4ef0fee6926d3dc471327eb2e014..0d32596ad0921304ca1b3b1a8d512fed00bbd103 100644 (file)
@@ -36,4 +36,11 @@ config EFI_VARS_PSTORE_DEFAULT_DISABLE
          backend for pstore by default. This setting can be overridden
          using the efivars module's pstore_disable parameter.
 
+config EFI_PARAMS_FROM_FDT
+       bool
+       help
+         Select this config option from the architecture Kconfig if
+         the EFI runtime support gets system table address, memory
+          map address, and other parameters from the device tree.
+
 endmenu
index 2e2fbdec0845414df2f32a8c0f862b4149ce3198..0c98165c1cd742f7726660e6a8038151abec02ad 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/efi.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
 #include <linux/io.h>
 
 struct efi __read_mostly efi = {
@@ -272,3 +274,80 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
        early_iounmap(config_tables, efi.systab->nr_tables * sz);
        return 0;
 }
+
+#ifdef CONFIG_EFI_PARAMS_FROM_FDT
+
+#define UEFI_PARAM(name, prop, field)                     \
+       {                                                  \
+               { name },                                  \
+               { prop },                                  \
+               offsetof(struct efi_fdt_params, field),    \
+               FIELD_SIZEOF(struct efi_fdt_params, field) \
+       }
+
+static __initdata struct {
+       const char name[32];
+       const char propname[32];
+       int offset;
+       int size;
+} dt_params[] = {
+       UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
+       UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
+       UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
+       UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
+       UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
+};
+
+struct param_info {
+       int verbose;
+       void *params;
+};
+
+static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
+                                      int depth, void *data)
+{
+       struct param_info *info = data;
+       void *prop, *dest;
+       unsigned long len;
+       u64 val;
+       int i;
+
+       if (depth != 1 ||
+           (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
+               return 0;
+
+       pr_info("Getting parameters from FDT:\n");
+
+       for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
+               prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len);
+               if (!prop) {
+                       pr_err("Can't find %s in device tree!\n",
+                              dt_params[i].name);
+                       return 0;
+               }
+               dest = info->params + dt_params[i].offset;
+
+               val = of_read_number(prop, len / sizeof(u32));
+
+               if (dt_params[i].size == sizeof(u32))
+                       *(u32 *)dest = val;
+               else
+                       *(u64 *)dest = val;
+
+               if (info->verbose)
+                       pr_info("  %s: 0x%0*llx\n", dt_params[i].name,
+                               dt_params[i].size * 2, val);
+       }
+       return 1;
+}
+
+int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose)
+{
+       struct param_info info;
+
+       info.verbose = verbose;
+       info.params = params;
+
+       return of_scan_flat_dt(fdt_find_uefi_params, &info);
+}
+#endif /* CONFIG_EFI_PARAMS_FROM_FDT */
index 115b15b27ba974e27c3e1b8120b8105a74f64af8..05111092d7284689c8e07390dfa782c463a279c4 100644 (file)
@@ -478,6 +478,14 @@ struct efi_memory_map {
        unsigned long desc_size;
 };
 
+struct efi_fdt_params {
+       u64 system_table;
+       u64 mmap;
+       u32 mmap_size;
+       u32 desc_size;
+       u32 desc_ver;
+};
+
 typedef struct {
        u32 revision;
        void *parent_handle;
@@ -605,6 +613,7 @@ extern void efi_initialize_iomem_resources(struct resource *code_resource,
 extern unsigned long efi_get_time(void);
 extern int efi_set_rtc_mmss(unsigned long nowtime);
 extern void efi_reserve_boot_services(void);
+extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose);
 extern struct efi_memory_map memmap;
 
 /**