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 /mm/percpu.c | |
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 'mm/percpu.c')
-rw-r--r-- | mm/percpu.c | 85 |
1 files changed, 84 insertions, 1 deletions
diff --git a/mm/percpu.c b/mm/percpu.c index fc6babe6e554..27b0f40a3ea8 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
@@ -1037,7 +1037,7 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, | |||
1037 | size_t static_size, size_t reserved_size, | 1037 | size_t static_size, size_t reserved_size, |
1038 | ssize_t dyn_size, ssize_t unit_size, | 1038 | ssize_t dyn_size, ssize_t unit_size, |
1039 | void *base_addr, | 1039 | void *base_addr, |
1040 | pcpu_populate_pte_fn_t populate_pte_fn) | 1040 | pcpu_fc_populate_pte_fn_t populate_pte_fn) |
1041 | { | 1041 | { |
1042 | static struct vm_struct first_vm; | 1042 | static struct vm_struct first_vm; |
1043 | static int smap[2], dmap[2]; | 1043 | static int smap[2], dmap[2]; |
@@ -1271,6 +1271,89 @@ ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size, | |||
1271 | } | 1271 | } |
1272 | 1272 | ||
1273 | /* | 1273 | /* |
1274 | * 4k page first chunk setup helper. | ||
1275 | */ | ||
1276 | static struct page **pcpu4k_pages __initdata; | ||
1277 | static int pcpu4k_nr_static_pages __initdata; | ||
1278 | |||
1279 | static struct page * __init pcpu4k_get_page(unsigned int cpu, int pageno) | ||
1280 | { | ||
1281 | if (pageno < pcpu4k_nr_static_pages) | ||
1282 | return pcpu4k_pages[cpu * pcpu4k_nr_static_pages + pageno]; | ||
1283 | return NULL; | ||
1284 | } | ||
1285 | |||
1286 | /** | ||
1287 | * pcpu_4k_first_chunk - map the first chunk using PAGE_SIZE pages | ||
1288 | * @static_size: the size of static percpu area in bytes | ||
1289 | * @reserved_size: the size of reserved percpu area in bytes | ||
1290 | * @alloc_fn: function to allocate percpu page, always called with PAGE_SIZE | ||
1291 | * @free_fn: funtion to free percpu page, always called with PAGE_SIZE | ||
1292 | * @populate_pte_fn: function to populate pte | ||
1293 | * | ||
1294 | * This is a helper to ease setting up embedded first percpu chunk and | ||
1295 | * can be called where pcpu_setup_first_chunk() is expected. | ||
1296 | * | ||
1297 | * This is the basic allocator. Static percpu area is allocated | ||
1298 | * page-by-page into vmalloc area. | ||
1299 | * | ||
1300 | * RETURNS: | ||
1301 | * The determined pcpu_unit_size which can be used to initialize | ||
1302 | * percpu access on success, -errno on failure. | ||
1303 | */ | ||
1304 | ssize_t __init pcpu_4k_first_chunk(size_t static_size, size_t reserved_size, | ||
1305 | pcpu_fc_alloc_fn_t alloc_fn, | ||
1306 | pcpu_fc_free_fn_t free_fn, | ||
1307 | pcpu_fc_populate_pte_fn_t populate_pte_fn) | ||
1308 | { | ||
1309 | size_t pages_size; | ||
1310 | unsigned int cpu; | ||
1311 | int i, j; | ||
1312 | ssize_t ret; | ||
1313 | |||
1314 | pcpu4k_nr_static_pages = PFN_UP(static_size); | ||
1315 | |||
1316 | /* unaligned allocations can't be freed, round up to page size */ | ||
1317 | pages_size = PFN_ALIGN(pcpu4k_nr_static_pages * num_possible_cpus() * | ||
1318 | sizeof(pcpu4k_pages[0])); | ||
1319 | pcpu4k_pages = alloc_bootmem(pages_size); | ||
1320 | |||
1321 | /* allocate and copy */ | ||
1322 | j = 0; | ||
1323 | for_each_possible_cpu(cpu) | ||
1324 | for (i = 0; i < pcpu4k_nr_static_pages; i++) { | ||
1325 | void *ptr; | ||
1326 | |||
1327 | ptr = alloc_fn(cpu, PAGE_SIZE); | ||
1328 | if (!ptr) { | ||
1329 | pr_warning("PERCPU: failed to allocate " | ||
1330 | "4k page for cpu%u\n", cpu); | ||
1331 | goto enomem; | ||
1332 | } | ||
1333 | |||
1334 | memcpy(ptr, __per_cpu_load + i * PAGE_SIZE, PAGE_SIZE); | ||
1335 | pcpu4k_pages[j++] = virt_to_page(ptr); | ||
1336 | } | ||
1337 | |||
1338 | /* we're ready, commit */ | ||
1339 | pr_info("PERCPU: Allocated %d 4k pages, static data %zu bytes\n", | ||
1340 | pcpu4k_nr_static_pages, static_size); | ||
1341 | |||
1342 | ret = pcpu_setup_first_chunk(pcpu4k_get_page, static_size, | ||
1343 | reserved_size, -1, | ||
1344 | -1, NULL, populate_pte_fn); | ||
1345 | goto out_free_ar; | ||
1346 | |||
1347 | enomem: | ||
1348 | while (--j >= 0) | ||
1349 | free_fn(page_address(pcpu4k_pages[j]), PAGE_SIZE); | ||
1350 | ret = -ENOMEM; | ||
1351 | out_free_ar: | ||
1352 | free_bootmem(__pa(pcpu4k_pages), pages_size); | ||
1353 | return ret; | ||
1354 | } | ||
1355 | |||
1356 | /* | ||
1274 | * Generic percpu area setup. | 1357 | * Generic percpu area setup. |
1275 | * | 1358 | * |
1276 | * The embedding helper is used because its behavior closely resembles | 1359 | * The embedding helper is used because its behavior closely resembles |