diff options
Diffstat (limited to 'arch/ia64/mm/contig.c')
-rw-r--r-- | arch/ia64/mm/contig.c | 99 |
1 files changed, 80 insertions, 19 deletions
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index 2f724d2bf299..54bf54059811 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c | |||
@@ -154,38 +154,99 @@ static void *cpu_data; | |||
154 | void * __cpuinit | 154 | void * __cpuinit |
155 | per_cpu_init (void) | 155 | per_cpu_init (void) |
156 | { | 156 | { |
157 | int cpu; | 157 | static bool first_time = true; |
158 | static int first_time=1; | 158 | void *cpu0_data = __cpu0_per_cpu; |
159 | unsigned int cpu; | ||
160 | |||
161 | if (!first_time) | ||
162 | goto skip; | ||
163 | first_time = false; | ||
159 | 164 | ||
160 | /* | 165 | /* |
161 | * get_free_pages() cannot be used before cpu_init() done. BSP | 166 | * get_free_pages() cannot be used before cpu_init() done. |
162 | * allocates "NR_CPUS" pages for all CPUs to avoid that AP calls | 167 | * BSP allocates PERCPU_PAGE_SIZE bytes for all possible CPUs |
163 | * get_zeroed_page(). | 168 | * to avoid that AP calls get_zeroed_page(). |
164 | */ | 169 | */ |
165 | if (first_time) { | 170 | for_each_possible_cpu(cpu) { |
166 | void *cpu0_data = __cpu0_per_cpu; | 171 | void *src = cpu == 0 ? cpu0_data : __phys_per_cpu_start; |
167 | 172 | ||
168 | first_time=0; | 173 | memcpy(cpu_data, src, __per_cpu_end - __per_cpu_start); |
174 | __per_cpu_offset[cpu] = (char *)cpu_data - __per_cpu_start; | ||
175 | per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu]; | ||
169 | 176 | ||
170 | __per_cpu_offset[0] = (char *) cpu0_data - __per_cpu_start; | 177 | /* |
171 | per_cpu(local_per_cpu_offset, 0) = __per_cpu_offset[0]; | 178 | * percpu area for cpu0 is moved from the __init area |
179 | * which is setup by head.S and used till this point. | ||
180 | * Update ar.k3. This move is ensures that percpu | ||
181 | * area for cpu0 is on the correct node and its | ||
182 | * virtual address isn't insanely far from other | ||
183 | * percpu areas which is important for congruent | ||
184 | * percpu allocator. | ||
185 | */ | ||
186 | if (cpu == 0) | ||
187 | ia64_set_kr(IA64_KR_PER_CPU_DATA, __pa(cpu_data) - | ||
188 | (unsigned long)__per_cpu_start); | ||
172 | 189 | ||
173 | for (cpu = 1; cpu < NR_CPUS; cpu++) { | 190 | cpu_data += PERCPU_PAGE_SIZE; |
174 | memcpy(cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start); | ||
175 | __per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start; | ||
176 | cpu_data += PERCPU_PAGE_SIZE; | ||
177 | per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu]; | ||
178 | } | ||
179 | } | 191 | } |
192 | skip: | ||
180 | return __per_cpu_start + __per_cpu_offset[smp_processor_id()]; | 193 | return __per_cpu_start + __per_cpu_offset[smp_processor_id()]; |
181 | } | 194 | } |
182 | 195 | ||
183 | static inline void | 196 | static inline void |
184 | alloc_per_cpu_data(void) | 197 | alloc_per_cpu_data(void) |
185 | { | 198 | { |
186 | cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS-1, | 199 | cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * num_possible_cpus(), |
187 | PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); | 200 | PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); |
188 | } | 201 | } |
202 | |||
203 | /** | ||
204 | * setup_per_cpu_areas - setup percpu areas | ||
205 | * | ||
206 | * Arch code has already allocated and initialized percpu areas. All | ||
207 | * this function has to do is to teach the determined layout to the | ||
208 | * dynamic percpu allocator, which happens to be more complex than | ||
209 | * creating whole new ones using helpers. | ||
210 | */ | ||
211 | void __init | ||
212 | setup_per_cpu_areas(void) | ||
213 | { | ||
214 | struct pcpu_alloc_info *ai; | ||
215 | struct pcpu_group_info *gi; | ||
216 | unsigned int cpu; | ||
217 | ssize_t static_size, reserved_size, dyn_size; | ||
218 | int rc; | ||
219 | |||
220 | ai = pcpu_alloc_alloc_info(1, num_possible_cpus()); | ||
221 | if (!ai) | ||
222 | panic("failed to allocate pcpu_alloc_info"); | ||
223 | gi = &ai->groups[0]; | ||
224 | |||
225 | /* units are assigned consecutively to possible cpus */ | ||
226 | for_each_possible_cpu(cpu) | ||
227 | gi->cpu_map[gi->nr_units++] = cpu; | ||
228 | |||
229 | /* set parameters */ | ||
230 | static_size = __per_cpu_end - __per_cpu_start; | ||
231 | reserved_size = PERCPU_MODULE_RESERVE; | ||
232 | dyn_size = PERCPU_PAGE_SIZE - static_size - reserved_size; | ||
233 | if (dyn_size < 0) | ||
234 | panic("percpu area overflow static=%zd reserved=%zd\n", | ||
235 | static_size, reserved_size); | ||
236 | |||
237 | ai->static_size = static_size; | ||
238 | ai->reserved_size = reserved_size; | ||
239 | ai->dyn_size = dyn_size; | ||
240 | ai->unit_size = PERCPU_PAGE_SIZE; | ||
241 | ai->atom_size = PAGE_SIZE; | ||
242 | ai->alloc_size = PERCPU_PAGE_SIZE; | ||
243 | |||
244 | rc = pcpu_setup_first_chunk(ai, __per_cpu_start + __per_cpu_offset[0]); | ||
245 | if (rc) | ||
246 | panic("failed to setup percpu area (err=%d)", rc); | ||
247 | |||
248 | pcpu_free_alloc_info(ai); | ||
249 | } | ||
189 | #else | 250 | #else |
190 | #define alloc_per_cpu_data() do { } while (0) | 251 | #define alloc_per_cpu_data() do { } while (0) |
191 | #endif /* CONFIG_SMP */ | 252 | #endif /* CONFIG_SMP */ |
@@ -270,8 +331,8 @@ paging_init (void) | |||
270 | 331 | ||
271 | map_size = PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * | 332 | map_size = PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * |
272 | sizeof(struct page)); | 333 | sizeof(struct page)); |
273 | vmalloc_end -= map_size; | 334 | VMALLOC_END -= map_size; |
274 | vmem_map = (struct page *) vmalloc_end; | 335 | vmem_map = (struct page *) VMALLOC_END; |
275 | efi_memmap_walk(create_mem_map_page_table, NULL); | 336 | efi_memmap_walk(create_mem_map_page_table, NULL); |
276 | 337 | ||
277 | /* | 338 | /* |