ARM: tegra: Remove legacy PCIe power supply properties
[cascardo/linux.git] / drivers / firmware / efi / fdt.c
1 /*
2  * FDT related Helper functions used by the EFI stub on multiple
3  * architectures. This should be #included by the EFI stub
4  * implementation files.
5  *
6  * Copyright 2013 Linaro Limited; author Roy Franz
7  *
8  * This file is part of the Linux kernel, and is made available
9  * under the terms of the GNU General Public License version 2.
10  *
11  */
12
13 static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
14                                unsigned long orig_fdt_size,
15                                void *fdt, int new_fdt_size, char *cmdline_ptr,
16                                u64 initrd_addr, u64 initrd_size,
17                                efi_memory_desc_t *memory_map,
18                                unsigned long map_size, unsigned long desc_size,
19                                u32 desc_ver)
20 {
21         int node, prev;
22         int status;
23         u32 fdt_val32;
24         u64 fdt_val64;
25
26         /*
27          * Copy definition of linux_banner here.  Since this code is
28          * built as part of the decompressor for ARM v7, pulling
29          * in version.c where linux_banner is defined for the
30          * kernel brings other kernel dependencies with it.
31          */
32         const char linux_banner[] =
33             "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
34             LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
35
36         /* Do some checks on provided FDT, if it exists*/
37         if (orig_fdt) {
38                 if (fdt_check_header(orig_fdt)) {
39                         pr_efi_err(sys_table, "Device Tree header not valid!\n");
40                         return EFI_LOAD_ERROR;
41                 }
42                 /*
43                  * We don't get the size of the FDT if we get if from a
44                  * configuration table.
45                  */
46                 if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) {
47                         pr_efi_err(sys_table, "Truncated device tree! foo!\n");
48                         return EFI_LOAD_ERROR;
49                 }
50         }
51
52         if (orig_fdt)
53                 status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
54         else
55                 status = fdt_create_empty_tree(fdt, new_fdt_size);
56
57         if (status != 0)
58                 goto fdt_set_fail;
59
60         /*
61          * Delete any memory nodes present. We must delete nodes which
62          * early_init_dt_scan_memory may try to use.
63          */
64         prev = 0;
65         for (;;) {
66                 const char *type, *name;
67                 int len;
68
69                 node = fdt_next_node(fdt, prev, NULL);
70                 if (node < 0)
71                         break;
72
73                 type = fdt_getprop(fdt, node, "device_type", &len);
74                 if (type && strncmp(type, "memory", len) == 0) {
75                         fdt_del_node(fdt, node);
76                         continue;
77                 }
78
79                 prev = node;
80         }
81
82         node = fdt_subnode_offset(fdt, 0, "chosen");
83         if (node < 0) {
84                 node = fdt_add_subnode(fdt, 0, "chosen");
85                 if (node < 0) {
86                         status = node; /* node is error code when negative */
87                         goto fdt_set_fail;
88                 }
89         }
90
91         if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) {
92                 status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
93                                      strlen(cmdline_ptr) + 1);
94                 if (status)
95                         goto fdt_set_fail;
96         }
97
98         /* Set initrd address/end in device tree, if present */
99         if (initrd_size != 0) {
100                 u64 initrd_image_end;
101                 u64 initrd_image_start = cpu_to_fdt64(initrd_addr);
102
103                 status = fdt_setprop(fdt, node, "linux,initrd-start",
104                                      &initrd_image_start, sizeof(u64));
105                 if (status)
106                         goto fdt_set_fail;
107                 initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size);
108                 status = fdt_setprop(fdt, node, "linux,initrd-end",
109                                      &initrd_image_end, sizeof(u64));
110                 if (status)
111                         goto fdt_set_fail;
112         }
113
114         /* Add FDT entries for EFI runtime services in chosen node. */
115         node = fdt_subnode_offset(fdt, 0, "chosen");
116         fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table);
117         status = fdt_setprop(fdt, node, "linux,uefi-system-table",
118                              &fdt_val64, sizeof(fdt_val64));
119         if (status)
120                 goto fdt_set_fail;
121
122         fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map);
123         status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
124                              &fdt_val64,  sizeof(fdt_val64));
125         if (status)
126                 goto fdt_set_fail;
127
128         fdt_val32 = cpu_to_fdt32(map_size);
129         status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
130                              &fdt_val32,  sizeof(fdt_val32));
131         if (status)
132                 goto fdt_set_fail;
133
134         fdt_val32 = cpu_to_fdt32(desc_size);
135         status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
136                              &fdt_val32, sizeof(fdt_val32));
137         if (status)
138                 goto fdt_set_fail;
139
140         fdt_val32 = cpu_to_fdt32(desc_ver);
141         status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
142                              &fdt_val32, sizeof(fdt_val32));
143         if (status)
144                 goto fdt_set_fail;
145
146         /*
147          * Add kernel version banner so stub/kernel match can be
148          * verified.
149          */
150         status = fdt_setprop_string(fdt, node, "linux,uefi-stub-kern-ver",
151                              linux_banner);
152         if (status)
153                 goto fdt_set_fail;
154
155         return EFI_SUCCESS;
156
157 fdt_set_fail:
158         if (status == -FDT_ERR_NOSPACE)
159                 return EFI_BUFFER_TOO_SMALL;
160
161         return EFI_LOAD_ERROR;
162 }
163
164 #ifndef EFI_FDT_ALIGN
165 #define EFI_FDT_ALIGN EFI_PAGE_SIZE
166 #endif
167
168 /*
169  * Allocate memory for a new FDT, then add EFI, commandline, and
170  * initrd related fields to the FDT.  This routine increases the
171  * FDT allocation size until the allocated memory is large
172  * enough.  EFI allocations are in EFI_PAGE_SIZE granules,
173  * which are fixed at 4K bytes, so in most cases the first
174  * allocation should succeed.
175  * EFI boot services are exited at the end of this function.
176  * There must be no allocations between the get_memory_map()
177  * call and the exit_boot_services() call, so the exiting of
178  * boot services is very tightly tied to the creation of the FDT
179  * with the final memory map in it.
180  */
181
182 efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
183                                             void *handle,
184                                             unsigned long *new_fdt_addr,
185                                             unsigned long max_addr,
186                                             u64 initrd_addr, u64 initrd_size,
187                                             char *cmdline_ptr,
188                                             unsigned long fdt_addr,
189                                             unsigned long fdt_size)
190 {
191         unsigned long map_size, desc_size;
192         u32 desc_ver;
193         unsigned long mmap_key;
194         efi_memory_desc_t *memory_map;
195         unsigned long new_fdt_size;
196         efi_status_t status;
197
198         /*
199          * Estimate size of new FDT, and allocate memory for it. We
200          * will allocate a bigger buffer if this ends up being too
201          * small, so a rough guess is OK here.
202          */
203         new_fdt_size = fdt_size + EFI_PAGE_SIZE;
204         while (1) {
205                 status = efi_high_alloc(sys_table, new_fdt_size, EFI_FDT_ALIGN,
206                                         new_fdt_addr, max_addr);
207                 if (status != EFI_SUCCESS) {
208                         pr_efi_err(sys_table, "Unable to allocate memory for new device tree.\n");
209                         goto fail;
210                 }
211
212                 /*
213                  * Now that we have done our final memory allocation (and free)
214                  * we can get the memory map key  needed for
215                  * exit_boot_services().
216                  */
217                 status = efi_get_memory_map(sys_table, &memory_map, &map_size,
218                                             &desc_size, &desc_ver, &mmap_key);
219                 if (status != EFI_SUCCESS)
220                         goto fail_free_new_fdt;
221
222                 status = update_fdt(sys_table,
223                                     (void *)fdt_addr, fdt_size,
224                                     (void *)*new_fdt_addr, new_fdt_size,
225                                     cmdline_ptr, initrd_addr, initrd_size,
226                                     memory_map, map_size, desc_size, desc_ver);
227
228                 /* Succeeding the first time is the expected case. */
229                 if (status == EFI_SUCCESS)
230                         break;
231
232                 if (status == EFI_BUFFER_TOO_SMALL) {
233                         /*
234                          * We need to allocate more space for the new
235                          * device tree, so free existing buffer that is
236                          * too small.  Also free memory map, as we will need
237                          * to get new one that reflects the free/alloc we do
238                          * on the device tree buffer.
239                          */
240                         efi_free(sys_table, new_fdt_size, *new_fdt_addr);
241                         sys_table->boottime->free_pool(memory_map);
242                         new_fdt_size += EFI_PAGE_SIZE;
243                 } else {
244                         pr_efi_err(sys_table, "Unable to constuct new device tree.\n");
245                         goto fail_free_mmap;
246                 }
247         }
248
249         /* Now we are ready to exit_boot_services.*/
250         status = sys_table->boottime->exit_boot_services(handle, mmap_key);
251
252
253         if (status == EFI_SUCCESS)
254                 return status;
255
256         pr_efi_err(sys_table, "Exit boot services failed.\n");
257
258 fail_free_mmap:
259         sys_table->boottime->free_pool(memory_map);
260
261 fail_free_new_fdt:
262         efi_free(sys_table, new_fdt_size, *new_fdt_addr);
263
264 fail:
265         return EFI_LOAD_ERROR;
266 }
267
268 static void *get_fdt(efi_system_table_t *sys_table)
269 {
270         efi_guid_t fdt_guid = DEVICE_TREE_GUID;
271         efi_config_table_t *tables;
272         void *fdt;
273         int i;
274
275         tables = (efi_config_table_t *) sys_table->tables;
276         fdt = NULL;
277
278         for (i = 0; i < sys_table->nr_tables; i++)
279                 if (efi_guidcmp(tables[i].guid, fdt_guid) == 0) {
280                         fdt = (void *) tables[i].table;
281                         break;
282          }
283
284         return fdt;
285 }