diff options
Diffstat (limited to 'arch/arm/kernel/devtree.c')
-rw-r--r-- | arch/arm/kernel/devtree.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index bee7f9d47f02..70f1bdeb241b 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c | |||
@@ -19,8 +19,10 @@ | |||
19 | #include <linux/of_irq.h> | 19 | #include <linux/of_irq.h> |
20 | #include <linux/of_platform.h> | 20 | #include <linux/of_platform.h> |
21 | 21 | ||
22 | #include <asm/cputype.h> | ||
22 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
23 | #include <asm/page.h> | 24 | #include <asm/page.h> |
25 | #include <asm/smp_plat.h> | ||
24 | #include <asm/mach/arch.h> | 26 | #include <asm/mach/arch.h> |
25 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
26 | 28 | ||
@@ -61,6 +63,108 @@ void __init arm_dt_memblock_reserve(void) | |||
61 | } | 63 | } |
62 | } | 64 | } |
63 | 65 | ||
66 | /* | ||
67 | * arm_dt_init_cpu_maps - Function retrieves cpu nodes from the device tree | ||
68 | * and builds the cpu logical map array containing MPIDR values related to | ||
69 | * logical cpus | ||
70 | * | ||
71 | * Updates the cpu possible mask with the number of parsed cpu nodes | ||
72 | */ | ||
73 | void __init arm_dt_init_cpu_maps(void) | ||
74 | { | ||
75 | /* | ||
76 | * Temp logical map is initialized with UINT_MAX values that are | ||
77 | * considered invalid logical map entries since the logical map must | ||
78 | * contain a list of MPIDR[23:0] values where MPIDR[31:24] must | ||
79 | * read as 0. | ||
80 | */ | ||
81 | struct device_node *cpu, *cpus; | ||
82 | u32 i, j, cpuidx = 1; | ||
83 | u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0; | ||
84 | |||
85 | u32 tmp_map[NR_CPUS] = { [0 ... NR_CPUS-1] = UINT_MAX }; | ||
86 | bool bootcpu_valid = false; | ||
87 | cpus = of_find_node_by_path("/cpus"); | ||
88 | |||
89 | if (!cpus) | ||
90 | return; | ||
91 | |||
92 | for_each_child_of_node(cpus, cpu) { | ||
93 | u32 hwid; | ||
94 | |||
95 | pr_debug(" * %s...\n", cpu->full_name); | ||
96 | /* | ||
97 | * A device tree containing CPU nodes with missing "reg" | ||
98 | * properties is considered invalid to build the | ||
99 | * cpu_logical_map. | ||
100 | */ | ||
101 | if (of_property_read_u32(cpu, "reg", &hwid)) { | ||
102 | pr_debug(" * %s missing reg property\n", | ||
103 | cpu->full_name); | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * 8 MSBs must be set to 0 in the DT since the reg property | ||
109 | * defines the MPIDR[23:0]. | ||
110 | */ | ||
111 | if (hwid & ~MPIDR_HWID_BITMASK) | ||
112 | return; | ||
113 | |||
114 | /* | ||
115 | * Duplicate MPIDRs are a recipe for disaster. | ||
116 | * Scan all initialized entries and check for | ||
117 | * duplicates. If any is found just bail out. | ||
118 | * temp values were initialized to UINT_MAX | ||
119 | * to avoid matching valid MPIDR[23:0] values. | ||
120 | */ | ||
121 | for (j = 0; j < cpuidx; j++) | ||
122 | if (WARN(tmp_map[j] == hwid, "Duplicate /cpu reg " | ||
123 | "properties in the DT\n")) | ||
124 | return; | ||
125 | |||
126 | /* | ||
127 | * Build a stashed array of MPIDR values. Numbering scheme | ||
128 | * requires that if detected the boot CPU must be assigned | ||
129 | * logical id 0. Other CPUs get sequential indexes starting | ||
130 | * from 1. If a CPU node with a reg property matching the | ||
131 | * boot CPU MPIDR is detected, this is recorded so that the | ||
132 | * logical map built from DT is validated and can be used | ||
133 | * to override the map created in smp_setup_processor_id(). | ||
134 | */ | ||
135 | if (hwid == mpidr) { | ||
136 | i = 0; | ||
137 | bootcpu_valid = true; | ||
138 | } else { | ||
139 | i = cpuidx++; | ||
140 | } | ||
141 | |||
142 | if (WARN(cpuidx > nr_cpu_ids, "DT /cpu %u nodes greater than " | ||
143 | "max cores %u, capping them\n", | ||
144 | cpuidx, nr_cpu_ids)) { | ||
145 | cpuidx = nr_cpu_ids; | ||
146 | break; | ||
147 | } | ||
148 | |||
149 | tmp_map[i] = hwid; | ||
150 | } | ||
151 | |||
152 | if (WARN(!bootcpu_valid, "DT missing boot CPU MPIDR[23:0], " | ||
153 | "fall back to default cpu_logical_map\n")) | ||
154 | return; | ||
155 | |||
156 | /* | ||
157 | * Since the boot CPU node contains proper data, and all nodes have | ||
158 | * a reg property, the DT CPU list can be considered valid and the | ||
159 | * logical map created in smp_setup_processor_id() can be overridden | ||
160 | */ | ||
161 | for (i = 0; i < cpuidx; i++) { | ||
162 | set_cpu_possible(i, true); | ||
163 | cpu_logical_map(i) = tmp_map[i]; | ||
164 | pr_debug("cpu logical map 0x%x\n", cpu_logical_map(i)); | ||
165 | } | ||
166 | } | ||
167 | |||
64 | /** | 168 | /** |
65 | * setup_machine_fdt - Machine setup when an dtb was passed to the kernel | 169 | * setup_machine_fdt - Machine setup when an dtb was passed to the kernel |
66 | * @dt_phys: physical address of dt blob | 170 | * @dt_phys: physical address of dt blob |