diff options
author | Tejun Heo <tj@kernel.org> | 2009-07-03 19:10:59 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2009-07-03 19:10:59 -0400 |
commit | d4b95f80399471e4bce5e992700ff7f06ef91f6a (patch) | |
tree | a7b97c549629ea1032c36a41048ea847a20b8d27 /arch | |
parent | 788e5abc5441e9046dd91c995c6f1f75bbd144bf (diff) |
x86,percpu: generalize 4k first chunk allocator
Generalize and move x86 setup_pcpu_4k() into pcpu_4k_first_chunk().
setup_pcpu_4k() now is a simple wrapper around the generalized
version. Other than taking size parameters and using arch supplied
callbacks to allocate/free memory, pcpu_4k_first_chunk() is identical
to the original implementation.
This simplifies arch code and will help converting more archs to
dynamic percpu allocator.
While at it, s/pcpu_populate_pte_fn_t/pcpu_fc_populate_pte_fn_t/ for
consistency.
[ Impact: code reorganization and generalization ]
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/setup_percpu.c | 78 |
1 files changed, 19 insertions, 59 deletions
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index 14728206fb52..ab896b31e80b 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
@@ -124,6 +124,19 @@ static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size, | |||
124 | } | 124 | } |
125 | 125 | ||
126 | /* | 126 | /* |
127 | * Helpers for first chunk memory allocation | ||
128 | */ | ||
129 | static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size) | ||
130 | { | ||
131 | return pcpu_alloc_bootmem(cpu, size, size); | ||
132 | } | ||
133 | |||
134 | static void __init pcpu_fc_free(void *ptr, size_t size) | ||
135 | { | ||
136 | free_bootmem(__pa(ptr), size); | ||
137 | } | ||
138 | |||
139 | /* | ||
127 | * Large page remap allocator | 140 | * Large page remap allocator |
128 | * | 141 | * |
129 | * This allocator uses PMD page as unit. A PMD page is allocated for | 142 | * This allocator uses PMD page as unit. A PMD page is allocated for |
@@ -346,22 +359,11 @@ static ssize_t __init setup_pcpu_embed(size_t static_size, bool chosen) | |||
346 | } | 359 | } |
347 | 360 | ||
348 | /* | 361 | /* |
349 | * 4k page allocator | 362 | * 4k allocator |
350 | * | 363 | * |
351 | * This is the basic allocator. Static percpu area is allocated | 364 | * Boring fallback 4k allocator. This allocator puts more pressure on |
352 | * page-by-page and most of initialization is done by the generic | 365 | * PTE TLBs but other than that behaves nicely on both UMA and NUMA. |
353 | * setup function. | ||
354 | */ | 366 | */ |
355 | static struct page **pcpu4k_pages __initdata; | ||
356 | static int pcpu4k_nr_static_pages __initdata; | ||
357 | |||
358 | static struct page * __init pcpu4k_get_page(unsigned int cpu, int pageno) | ||
359 | { | ||
360 | if (pageno < pcpu4k_nr_static_pages) | ||
361 | return pcpu4k_pages[cpu * pcpu4k_nr_static_pages + pageno]; | ||
362 | return NULL; | ||
363 | } | ||
364 | |||
365 | static void __init pcpu4k_populate_pte(unsigned long addr) | 367 | static void __init pcpu4k_populate_pte(unsigned long addr) |
366 | { | 368 | { |
367 | populate_extra_pte(addr); | 369 | populate_extra_pte(addr); |
@@ -369,51 +371,9 @@ static void __init pcpu4k_populate_pte(unsigned long addr) | |||
369 | 371 | ||
370 | static ssize_t __init setup_pcpu_4k(size_t static_size) | 372 | static ssize_t __init setup_pcpu_4k(size_t static_size) |
371 | { | 373 | { |
372 | size_t pages_size; | 374 | return pcpu_4k_first_chunk(static_size, PERCPU_FIRST_CHUNK_RESERVE, |
373 | unsigned int cpu; | 375 | pcpu_fc_alloc, pcpu_fc_free, |
374 | int i, j; | 376 | pcpu4k_populate_pte); |
375 | ssize_t ret; | ||
376 | |||
377 | pcpu4k_nr_static_pages = PFN_UP(static_size); | ||
378 | |||
379 | /* unaligned allocations can't be freed, round up to page size */ | ||
380 | pages_size = PFN_ALIGN(pcpu4k_nr_static_pages * num_possible_cpus() | ||
381 | * sizeof(pcpu4k_pages[0])); | ||
382 | pcpu4k_pages = alloc_bootmem(pages_size); | ||
383 | |||
384 | /* allocate and copy */ | ||
385 | j = 0; | ||
386 | for_each_possible_cpu(cpu) | ||
387 | for (i = 0; i < pcpu4k_nr_static_pages; i++) { | ||
388 | void *ptr; | ||
389 | |||
390 | ptr = pcpu_alloc_bootmem(cpu, PAGE_SIZE, PAGE_SIZE); | ||
391 | if (!ptr) { | ||
392 | pr_warning("PERCPU: failed to allocate " | ||
393 | "4k page for cpu%u\n", cpu); | ||
394 | goto enomem; | ||
395 | } | ||
396 | |||
397 | memcpy(ptr, __per_cpu_load + i * PAGE_SIZE, PAGE_SIZE); | ||
398 | pcpu4k_pages[j++] = virt_to_page(ptr); | ||
399 | } | ||
400 | |||
401 | /* we're ready, commit */ | ||
402 | pr_info("PERCPU: Allocated %d 4k pages, static data %zu bytes\n", | ||
403 | pcpu4k_nr_static_pages, static_size); | ||
404 | |||
405 | ret = pcpu_setup_first_chunk(pcpu4k_get_page, static_size, | ||
406 | PERCPU_FIRST_CHUNK_RESERVE, -1, | ||
407 | -1, NULL, pcpu4k_populate_pte); | ||
408 | goto out_free_ar; | ||
409 | |||
410 | enomem: | ||
411 | while (--j >= 0) | ||
412 | free_bootmem(__pa(page_address(pcpu4k_pages[j])), PAGE_SIZE); | ||
413 | ret = -ENOMEM; | ||
414 | out_free_ar: | ||
415 | free_bootmem(__pa(pcpu4k_pages), pages_size); | ||
416 | return ret; | ||
417 | } | 377 | } |
418 | 378 | ||
419 | /* for explicit first chunk allocator selection */ | 379 | /* for explicit first chunk allocator selection */ |