diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/kernel/devtree.c | 145 | ||||
-rw-r--r-- | arch/arm/kernel/head-common.S | 24 | ||||
-rw-r--r-- | arch/arm/kernel/head.S | 8 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 90 |
5 files changed, 226 insertions, 42 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 8d95446150a..908c78cb1d1 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -44,6 +44,7 @@ obj-$(CONFIG_ARM_THUMBEE) += thumbee.o | |||
44 | obj-$(CONFIG_KGDB) += kgdb.o | 44 | obj-$(CONFIG_KGDB) += kgdb.o |
45 | obj-$(CONFIG_ARM_UNWIND) += unwind.o | 45 | obj-$(CONFIG_ARM_UNWIND) += unwind.o |
46 | obj-$(CONFIG_HAVE_TCM) += tcm.o | 46 | obj-$(CONFIG_HAVE_TCM) += tcm.o |
47 | obj-$(CONFIG_OF) += devtree.o | ||
47 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | 48 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o |
48 | obj-$(CONFIG_SWP_EMULATE) += swp_emulate.o | 49 | obj-$(CONFIG_SWP_EMULATE) += swp_emulate.o |
49 | CFLAGS_swp_emulate.o := -Wa,-march=armv7-a | 50 | CFLAGS_swp_emulate.o := -Wa,-march=armv7-a |
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c new file mode 100644 index 00000000000..a701e4226a6 --- /dev/null +++ b/arch/arm/kernel/devtree.c | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/devtree.c | ||
3 | * | ||
4 | * Copyright (C) 2009 Canonical Ltd. <jeremy.kerr@canonical.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/bootmem.h> | ||
16 | #include <linux/memblock.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_fdt.h> | ||
19 | #include <linux/of_irq.h> | ||
20 | #include <linux/of_platform.h> | ||
21 | |||
22 | #include <asm/setup.h> | ||
23 | #include <asm/page.h> | ||
24 | #include <asm/mach/arch.h> | ||
25 | #include <asm/mach-types.h> | ||
26 | |||
27 | void __init early_init_dt_add_memory_arch(u64 base, u64 size) | ||
28 | { | ||
29 | arm_add_memory(base, size); | ||
30 | } | ||
31 | |||
32 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) | ||
33 | { | ||
34 | return alloc_bootmem_align(size, align); | ||
35 | } | ||
36 | |||
37 | void __init arm_dt_memblock_reserve(void) | ||
38 | { | ||
39 | u64 *reserve_map, base, size; | ||
40 | |||
41 | if (!initial_boot_params) | ||
42 | return; | ||
43 | |||
44 | /* Reserve the dtb region */ | ||
45 | memblock_reserve(virt_to_phys(initial_boot_params), | ||
46 | be32_to_cpu(initial_boot_params->totalsize)); | ||
47 | |||
48 | /* | ||
49 | * Process the reserve map. This will probably overlap the initrd | ||
50 | * and dtb locations which are already reserved, but overlaping | ||
51 | * doesn't hurt anything | ||
52 | */ | ||
53 | reserve_map = ((void*)initial_boot_params) + | ||
54 | be32_to_cpu(initial_boot_params->off_mem_rsvmap); | ||
55 | while (1) { | ||
56 | base = be64_to_cpup(reserve_map++); | ||
57 | size = be64_to_cpup(reserve_map++); | ||
58 | if (!size) | ||
59 | break; | ||
60 | memblock_reserve(base, size); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * setup_machine_fdt - Machine setup when an dtb was passed to the kernel | ||
66 | * @dt_phys: physical address of dt blob | ||
67 | * | ||
68 | * If a dtb was passed to the kernel in r2, then use it to choose the | ||
69 | * correct machine_desc and to setup the system. | ||
70 | */ | ||
71 | struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) | ||
72 | { | ||
73 | struct boot_param_header *devtree; | ||
74 | struct machine_desc *mdesc, *mdesc_best = NULL; | ||
75 | unsigned int score, mdesc_score = ~1; | ||
76 | unsigned long dt_root; | ||
77 | const char *model; | ||
78 | |||
79 | devtree = phys_to_virt(dt_phys); | ||
80 | |||
81 | /* check device tree validity */ | ||
82 | if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) | ||
83 | return NULL; | ||
84 | |||
85 | /* Search the mdescs for the 'best' compatible value match */ | ||
86 | initial_boot_params = devtree; | ||
87 | dt_root = of_get_flat_dt_root(); | ||
88 | for_each_machine_desc(mdesc) { | ||
89 | score = of_flat_dt_match(dt_root, mdesc->dt_compat); | ||
90 | if (score > 0 && score < mdesc_score) { | ||
91 | mdesc_best = mdesc; | ||
92 | mdesc_score = score; | ||
93 | } | ||
94 | } | ||
95 | if (!mdesc_best) { | ||
96 | const char *prop; | ||
97 | long size; | ||
98 | |||
99 | early_print("\nError: unrecognized/unsupported " | ||
100 | "device tree compatible list:\n[ "); | ||
101 | |||
102 | prop = of_get_flat_dt_prop(dt_root, "compatible", &size); | ||
103 | while (size > 0) { | ||
104 | early_print("'%s' ", prop); | ||
105 | size -= strlen(prop) + 1; | ||
106 | prop += strlen(prop) + 1; | ||
107 | } | ||
108 | early_print("]\n\n"); | ||
109 | |||
110 | dump_machine_table(); /* does not return */ | ||
111 | } | ||
112 | |||
113 | model = of_get_flat_dt_prop(dt_root, "model", NULL); | ||
114 | if (!model) | ||
115 | model = of_get_flat_dt_prop(dt_root, "compatible", NULL); | ||
116 | if (!model) | ||
117 | model = "<unknown>"; | ||
118 | pr_info("Machine: %s, model: %s\n", mdesc_best->name, model); | ||
119 | |||
120 | /* Retrieve various information from the /chosen node */ | ||
121 | of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); | ||
122 | /* Initialize {size,address}-cells info */ | ||
123 | of_scan_flat_dt(early_init_dt_scan_root, NULL); | ||
124 | /* Setup memory, calling early_init_dt_add_memory_arch */ | ||
125 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); | ||
126 | |||
127 | /* Change machine number to match the mdesc we're using */ | ||
128 | __machine_arch_type = mdesc_best->nr; | ||
129 | |||
130 | return mdesc_best; | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq# | ||
135 | * | ||
136 | * Currently the mapping mechanism is trivial; simple flat hwirq numbers are | ||
137 | * mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not | ||
138 | * supported. | ||
139 | */ | ||
140 | unsigned int irq_create_of_mapping(struct device_node *controller, | ||
141 | const u32 *intspec, unsigned int intsize) | ||
142 | { | ||
143 | return intspec[0]; | ||
144 | } | ||
145 | EXPORT_SYMBOL_GPL(irq_create_of_mapping); | ||
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S index c84b57d27d0..854bd22380d 100644 --- a/arch/arm/kernel/head-common.S +++ b/arch/arm/kernel/head-common.S | |||
@@ -15,6 +15,12 @@ | |||
15 | #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) | 15 | #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) |
16 | #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2) | 16 | #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2) |
17 | 17 | ||
18 | #ifdef CONFIG_CPU_BIG_ENDIAN | ||
19 | #define OF_DT_MAGIC 0xd00dfeed | ||
20 | #else | ||
21 | #define OF_DT_MAGIC 0xedfe0dd0 /* 0xd00dfeed in big-endian */ | ||
22 | #endif | ||
23 | |||
18 | /* | 24 | /* |
19 | * Exception handling. Something went wrong and we can't proceed. We | 25 | * Exception handling. Something went wrong and we can't proceed. We |
20 | * ought to tell the user, but since we don't have any guarantee that | 26 | * ought to tell the user, but since we don't have any guarantee that |
@@ -28,20 +34,26 @@ | |||
28 | 34 | ||
29 | /* Determine validity of the r2 atags pointer. The heuristic requires | 35 | /* Determine validity of the r2 atags pointer. The heuristic requires |
30 | * that the pointer be aligned, in the first 16k of physical RAM and | 36 | * that the pointer be aligned, in the first 16k of physical RAM and |
31 | * that the ATAG_CORE marker is first and present. Future revisions | 37 | * that the ATAG_CORE marker is first and present. If CONFIG_OF_FLATTREE |
38 | * is selected, then it will also accept a dtb pointer. Future revisions | ||
32 | * of this function may be more lenient with the physical address and | 39 | * of this function may be more lenient with the physical address and |
33 | * may also be able to move the ATAGS block if necessary. | 40 | * may also be able to move the ATAGS block if necessary. |
34 | * | 41 | * |
35 | * Returns: | 42 | * Returns: |
36 | * r2 either valid atags pointer, or zero | 43 | * r2 either valid atags pointer, valid dtb pointer, or zero |
37 | * r5, r6 corrupted | 44 | * r5, r6 corrupted |
38 | */ | 45 | */ |
39 | __vet_atags: | 46 | __vet_atags: |
40 | tst r2, #0x3 @ aligned? | 47 | tst r2, #0x3 @ aligned? |
41 | bne 1f | 48 | bne 1f |
42 | 49 | ||
43 | ldr r5, [r2, #0] @ is first tag ATAG_CORE? | 50 | ldr r5, [r2, #0] |
44 | cmp r5, #ATAG_CORE_SIZE | 51 | #ifdef CONFIG_OF_FLATTREE |
52 | ldr r6, =OF_DT_MAGIC @ is it a DTB? | ||
53 | cmp r5, r6 | ||
54 | beq 2f | ||
55 | #endif | ||
56 | cmp r5, #ATAG_CORE_SIZE @ is first tag ATAG_CORE? | ||
45 | cmpne r5, #ATAG_CORE_SIZE_EMPTY | 57 | cmpne r5, #ATAG_CORE_SIZE_EMPTY |
46 | bne 1f | 58 | bne 1f |
47 | ldr r5, [r2, #4] | 59 | ldr r5, [r2, #4] |
@@ -49,7 +61,7 @@ __vet_atags: | |||
49 | cmp r5, r6 | 61 | cmp r5, r6 |
50 | bne 1f | 62 | bne 1f |
51 | 63 | ||
52 | mov pc, lr @ atag pointer is ok | 64 | 2: mov pc, lr @ atag/dtb pointer is ok |
53 | 65 | ||
54 | 1: mov r2, #0 | 66 | 1: mov r2, #0 |
55 | mov pc, lr | 67 | mov pc, lr |
@@ -61,7 +73,7 @@ ENDPROC(__vet_atags) | |||
61 | * | 73 | * |
62 | * r0 = cp#15 control register | 74 | * r0 = cp#15 control register |
63 | * r1 = machine ID | 75 | * r1 = machine ID |
64 | * r2 = atags pointer | 76 | * r2 = atags/dtb pointer |
65 | * r9 = processor ID | 77 | * r9 = processor ID |
66 | */ | 78 | */ |
67 | __INIT | 79 | __INIT |
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index c9173cfbbc7..a5e5c5b9b48 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -59,7 +59,7 @@ | |||
59 | * | 59 | * |
60 | * This is normally called from the decompressor code. The requirements | 60 | * This is normally called from the decompressor code. The requirements |
61 | * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, | 61 | * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, |
62 | * r1 = machine nr, r2 = atags pointer. | 62 | * r1 = machine nr, r2 = atags or dtb pointer. |
63 | * | 63 | * |
64 | * This code is mostly position independent, so if you link the kernel at | 64 | * This code is mostly position independent, so if you link the kernel at |
65 | * 0xc0008000, you call this at __pa(0xc0008000). | 65 | * 0xc0008000, you call this at __pa(0xc0008000). |
@@ -91,7 +91,7 @@ ENTRY(stext) | |||
91 | #endif | 91 | #endif |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * r1 = machine no, r2 = atags, | 94 | * r1 = machine no, r2 = atags or dtb, |
95 | * r8 = phys_offset, r9 = cpuid, r10 = procinfo | 95 | * r8 = phys_offset, r9 = cpuid, r10 = procinfo |
96 | */ | 96 | */ |
97 | bl __vet_atags | 97 | bl __vet_atags |
@@ -339,7 +339,7 @@ __secondary_data: | |||
339 | * | 339 | * |
340 | * r0 = cp#15 control register | 340 | * r0 = cp#15 control register |
341 | * r1 = machine ID | 341 | * r1 = machine ID |
342 | * r2 = atags pointer | 342 | * r2 = atags or dtb pointer |
343 | * r4 = page table pointer | 343 | * r4 = page table pointer |
344 | * r9 = processor ID | 344 | * r9 = processor ID |
345 | * r13 = *virtual* address to jump to upon completion | 345 | * r13 = *virtual* address to jump to upon completion |
@@ -376,7 +376,7 @@ ENDPROC(__enable_mmu) | |||
376 | * | 376 | * |
377 | * r0 = cp#15 control register | 377 | * r0 = cp#15 control register |
378 | * r1 = machine ID | 378 | * r1 = machine ID |
379 | * r2 = atags pointer | 379 | * r2 = atags or dtb pointer |
380 | * r9 = processor ID | 380 | * r9 = processor ID |
381 | * r13 = *virtual* address to jump to upon completion | 381 | * r13 = *virtual* address to jump to upon completion |
382 | * | 382 | * |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 6dce209a623..ed11fb08b05 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/screen_info.h> | 20 | #include <linux/screen_info.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/kexec.h> | 22 | #include <linux/kexec.h> |
23 | #include <linux/of_fdt.h> | ||
23 | #include <linux/crash_dump.h> | 24 | #include <linux/crash_dump.h> |
24 | #include <linux/root_dev.h> | 25 | #include <linux/root_dev.h> |
25 | #include <linux/cpu.h> | 26 | #include <linux/cpu.h> |
@@ -42,6 +43,7 @@ | |||
42 | #include <asm/cachetype.h> | 43 | #include <asm/cachetype.h> |
43 | #include <asm/tlbflush.h> | 44 | #include <asm/tlbflush.h> |
44 | 45 | ||
46 | #include <asm/prom.h> | ||
45 | #include <asm/mach/arch.h> | 47 | #include <asm/mach/arch.h> |
46 | #include <asm/mach/irq.h> | 48 | #include <asm/mach/irq.h> |
47 | #include <asm/mach/time.h> | 49 | #include <asm/mach/time.h> |
@@ -309,7 +311,7 @@ static void __init cacheid_init(void) | |||
309 | */ | 311 | */ |
310 | extern struct proc_info_list *lookup_processor_type(unsigned int); | 312 | extern struct proc_info_list *lookup_processor_type(unsigned int); |
311 | 313 | ||
312 | static void __init early_print(const char *str, ...) | 314 | void __init early_print(const char *str, ...) |
313 | { | 315 | { |
314 | extern void printascii(const char *); | 316 | extern void printascii(const char *); |
315 | char buf[256]; | 317 | char buf[256]; |
@@ -439,25 +441,12 @@ void cpu_init(void) | |||
439 | : "r14"); | 441 | : "r14"); |
440 | } | 442 | } |
441 | 443 | ||
442 | static struct machine_desc * __init setup_machine(unsigned int nr) | 444 | void __init dump_machine_table(void) |
443 | { | 445 | { |
444 | extern struct machine_desc __arch_info_begin[], __arch_info_end[]; | ||
445 | struct machine_desc *p; | 446 | struct machine_desc *p; |
446 | 447 | ||
447 | /* | 448 | early_print("Available machine support:\n\nID (hex)\tNAME\n"); |
448 | * locate machine in the list of supported machines. | 449 | for_each_machine_desc(p) |
449 | */ | ||
450 | for (p = __arch_info_begin; p < __arch_info_end; p++) | ||
451 | if (nr == p->nr) { | ||
452 | printk("Machine: %s\n", p->name); | ||
453 | return p; | ||
454 | } | ||
455 | |||
456 | early_print("\n" | ||
457 | "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n" | ||
458 | "Available machine support:\n\nID (hex)\tNAME\n", nr); | ||
459 | |||
460 | for (p = __arch_info_begin; p < __arch_info_end; p++) | ||
461 | early_print("%08x\t%s\n", p->nr, p->name); | 450 | early_print("%08x\t%s\n", p->nr, p->name); |
462 | 451 | ||
463 | early_print("\nPlease check your kernel config and/or bootloader.\n"); | 452 | early_print("\nPlease check your kernel config and/or bootloader.\n"); |
@@ -466,7 +455,7 @@ static struct machine_desc * __init setup_machine(unsigned int nr) | |||
466 | /* can't use cpu_relax() here as it may require MMU setup */; | 455 | /* can't use cpu_relax() here as it may require MMU setup */; |
467 | } | 456 | } |
468 | 457 | ||
469 | static int __init arm_add_memory(phys_addr_t start, unsigned long size) | 458 | int __init arm_add_memory(phys_addr_t start, unsigned long size) |
470 | { | 459 | { |
471 | struct membank *bank = &meminfo.bank[meminfo.nr_banks]; | 460 | struct membank *bank = &meminfo.bank[meminfo.nr_banks]; |
472 | 461 | ||
@@ -801,23 +790,29 @@ static void __init squash_mem_tags(struct tag *tag) | |||
801 | tag->hdr.tag = ATAG_NONE; | 790 | tag->hdr.tag = ATAG_NONE; |
802 | } | 791 | } |
803 | 792 | ||
804 | void __init setup_arch(char **cmdline_p) | 793 | static struct machine_desc * __init setup_machine_tags(unsigned int nr) |
805 | { | 794 | { |
806 | struct tag *tags = (struct tag *)&init_tags; | 795 | struct tag *tags = (struct tag *)&init_tags; |
807 | struct machine_desc *mdesc; | 796 | struct machine_desc *mdesc = NULL, *p; |
808 | char *from = default_command_line; | 797 | char *from = default_command_line; |
809 | 798 | ||
810 | init_tags.mem.start = PHYS_OFFSET; | 799 | init_tags.mem.start = PHYS_OFFSET; |
811 | 800 | ||
812 | unwind_init(); | 801 | /* |
813 | 802 | * locate machine in the list of supported machines. | |
814 | setup_processor(); | 803 | */ |
815 | mdesc = setup_machine(machine_arch_type); | 804 | for_each_machine_desc(p) |
816 | machine_desc = mdesc; | 805 | if (nr == p->nr) { |
817 | machine_name = mdesc->name; | 806 | printk("Machine: %s\n", p->name); |
807 | mdesc = p; | ||
808 | break; | ||
809 | } | ||
818 | 810 | ||
819 | if (mdesc->soft_reboot) | 811 | if (!mdesc) { |
820 | reboot_setup("s"); | 812 | early_print("\nError: unrecognized/unsupported machine ID" |
813 | " (r1 = 0x%08x).\n\n", nr); | ||
814 | dump_machine_table(); /* does not return */ | ||
815 | } | ||
821 | 816 | ||
822 | if (__atags_pointer) | 817 | if (__atags_pointer) |
823 | tags = phys_to_virt(__atags_pointer); | 818 | tags = phys_to_virt(__atags_pointer); |
@@ -849,8 +844,17 @@ void __init setup_arch(char **cmdline_p) | |||
849 | if (tags->hdr.tag != ATAG_CORE) | 844 | if (tags->hdr.tag != ATAG_CORE) |
850 | convert_to_tag_list(tags); | 845 | convert_to_tag_list(tags); |
851 | #endif | 846 | #endif |
852 | if (tags->hdr.tag != ATAG_CORE) | 847 | |
848 | if (tags->hdr.tag != ATAG_CORE) { | ||
849 | #if defined(CONFIG_OF) | ||
850 | /* | ||
851 | * If CONFIG_OF is set, then assume this is a reasonably | ||
852 | * modern system that should pass boot parameters | ||
853 | */ | ||
854 | early_print("Warning: Neither atags nor dtb found\n"); | ||
855 | #endif | ||
853 | tags = (struct tag *)&init_tags; | 856 | tags = (struct tag *)&init_tags; |
857 | } | ||
854 | 858 | ||
855 | if (mdesc->fixup) | 859 | if (mdesc->fixup) |
856 | mdesc->fixup(mdesc, tags, &from, &meminfo); | 860 | mdesc->fixup(mdesc, tags, &from, &meminfo); |
@@ -862,14 +866,34 @@ void __init setup_arch(char **cmdline_p) | |||
862 | parse_tags(tags); | 866 | parse_tags(tags); |
863 | } | 867 | } |
864 | 868 | ||
869 | /* parse_early_param needs a boot_command_line */ | ||
870 | strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); | ||
871 | |||
872 | return mdesc; | ||
873 | } | ||
874 | |||
875 | |||
876 | void __init setup_arch(char **cmdline_p) | ||
877 | { | ||
878 | struct machine_desc *mdesc; | ||
879 | |||
880 | unwind_init(); | ||
881 | |||
882 | setup_processor(); | ||
883 | mdesc = setup_machine_fdt(__atags_pointer); | ||
884 | if (!mdesc) | ||
885 | mdesc = setup_machine_tags(machine_arch_type); | ||
886 | machine_desc = mdesc; | ||
887 | machine_name = mdesc->name; | ||
888 | |||
889 | if (mdesc->soft_reboot) | ||
890 | reboot_setup("s"); | ||
891 | |||
865 | init_mm.start_code = (unsigned long) _text; | 892 | init_mm.start_code = (unsigned long) _text; |
866 | init_mm.end_code = (unsigned long) _etext; | 893 | init_mm.end_code = (unsigned long) _etext; |
867 | init_mm.end_data = (unsigned long) _edata; | 894 | init_mm.end_data = (unsigned long) _edata; |
868 | init_mm.brk = (unsigned long) _end; | 895 | init_mm.brk = (unsigned long) _end; |
869 | 896 | ||
870 | /* parse_early_param needs a boot_command_line */ | ||
871 | strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); | ||
872 | |||
873 | /* populate cmd_line too for later use, preserving boot_command_line */ | 897 | /* populate cmd_line too for later use, preserving boot_command_line */ |
874 | strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); | 898 | strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); |
875 | *cmdline_p = cmd_line; | 899 | *cmdline_p = cmd_line; |
@@ -881,6 +905,8 @@ void __init setup_arch(char **cmdline_p) | |||
881 | paging_init(mdesc); | 905 | paging_init(mdesc); |
882 | request_standard_resources(mdesc); | 906 | request_standard_resources(mdesc); |
883 | 907 | ||
908 | unflatten_device_tree(); | ||
909 | |||
884 | #ifdef CONFIG_SMP | 910 | #ifdef CONFIG_SMP |
885 | if (is_smp()) | 911 | if (is_smp()) |
886 | smp_init_cpus(); | 912 | smp_init_cpus(); |