diff options
Diffstat (limited to 'mm/percpu.c')
-rw-r--r-- | mm/percpu.c | 71 |
1 files changed, 54 insertions, 17 deletions
diff --git a/mm/percpu.c b/mm/percpu.c index 27b0f40a3ea8..f3fe7bc7378f 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
@@ -632,6 +632,13 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size, | |||
632 | pcpu_unmap(chunk, unmap_start, unmap_end, flush); | 632 | pcpu_unmap(chunk, unmap_start, unmap_end, flush); |
633 | } | 633 | } |
634 | 634 | ||
635 | static int __pcpu_map_pages(unsigned long addr, struct page **pages, | ||
636 | int nr_pages) | ||
637 | { | ||
638 | return map_kernel_range_noflush(addr, nr_pages << PAGE_SHIFT, | ||
639 | PAGE_KERNEL, pages); | ||
640 | } | ||
641 | |||
635 | /** | 642 | /** |
636 | * pcpu_map - map pages into a pcpu_chunk | 643 | * pcpu_map - map pages into a pcpu_chunk |
637 | * @chunk: chunk of interest | 644 | * @chunk: chunk of interest |
@@ -651,11 +658,9 @@ static int pcpu_map(struct pcpu_chunk *chunk, int page_start, int page_end) | |||
651 | WARN_ON(chunk->immutable); | 658 | WARN_ON(chunk->immutable); |
652 | 659 | ||
653 | for_each_possible_cpu(cpu) { | 660 | for_each_possible_cpu(cpu) { |
654 | err = map_kernel_range_noflush( | 661 | err = __pcpu_map_pages(pcpu_chunk_addr(chunk, cpu, page_start), |
655 | pcpu_chunk_addr(chunk, cpu, page_start), | 662 | pcpu_chunk_pagep(chunk, cpu, page_start), |
656 | (page_end - page_start) << PAGE_SHIFT, | 663 | page_end - page_start); |
657 | PAGE_KERNEL, | ||
658 | pcpu_chunk_pagep(chunk, cpu, page_start)); | ||
659 | if (err < 0) | 664 | if (err < 0) |
660 | return err; | 665 | return err; |
661 | } | 666 | } |
@@ -1274,12 +1279,12 @@ ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size, | |||
1274 | * 4k page first chunk setup helper. | 1279 | * 4k page first chunk setup helper. |
1275 | */ | 1280 | */ |
1276 | static struct page **pcpu4k_pages __initdata; | 1281 | static struct page **pcpu4k_pages __initdata; |
1277 | static int pcpu4k_nr_static_pages __initdata; | 1282 | static int pcpu4k_unit_pages __initdata; |
1278 | 1283 | ||
1279 | static struct page * __init pcpu4k_get_page(unsigned int cpu, int pageno) | 1284 | static struct page * __init pcpu4k_get_page(unsigned int cpu, int pageno) |
1280 | { | 1285 | { |
1281 | if (pageno < pcpu4k_nr_static_pages) | 1286 | if (pageno < pcpu4k_unit_pages) |
1282 | return pcpu4k_pages[cpu * pcpu4k_nr_static_pages + pageno]; | 1287 | return pcpu4k_pages[cpu * pcpu4k_unit_pages + pageno]; |
1283 | return NULL; | 1288 | return NULL; |
1284 | } | 1289 | } |
1285 | 1290 | ||
@@ -1306,22 +1311,24 @@ ssize_t __init pcpu_4k_first_chunk(size_t static_size, size_t reserved_size, | |||
1306 | pcpu_fc_free_fn_t free_fn, | 1311 | pcpu_fc_free_fn_t free_fn, |
1307 | pcpu_fc_populate_pte_fn_t populate_pte_fn) | 1312 | pcpu_fc_populate_pte_fn_t populate_pte_fn) |
1308 | { | 1313 | { |
1314 | static struct vm_struct vm; | ||
1309 | size_t pages_size; | 1315 | size_t pages_size; |
1310 | unsigned int cpu; | 1316 | unsigned int cpu; |
1311 | int i, j; | 1317 | int i, j; |
1312 | ssize_t ret; | 1318 | ssize_t ret; |
1313 | 1319 | ||
1314 | pcpu4k_nr_static_pages = PFN_UP(static_size); | 1320 | pcpu4k_unit_pages = PFN_UP(max_t(size_t, static_size + reserved_size, |
1321 | PCPU_MIN_UNIT_SIZE)); | ||
1315 | 1322 | ||
1316 | /* unaligned allocations can't be freed, round up to page size */ | 1323 | /* unaligned allocations can't be freed, round up to page size */ |
1317 | pages_size = PFN_ALIGN(pcpu4k_nr_static_pages * num_possible_cpus() * | 1324 | pages_size = PFN_ALIGN(pcpu4k_unit_pages * num_possible_cpus() * |
1318 | sizeof(pcpu4k_pages[0])); | 1325 | sizeof(pcpu4k_pages[0])); |
1319 | pcpu4k_pages = alloc_bootmem(pages_size); | 1326 | pcpu4k_pages = alloc_bootmem(pages_size); |
1320 | 1327 | ||
1321 | /* allocate and copy */ | 1328 | /* allocate pages */ |
1322 | j = 0; | 1329 | j = 0; |
1323 | for_each_possible_cpu(cpu) | 1330 | for_each_possible_cpu(cpu) |
1324 | for (i = 0; i < pcpu4k_nr_static_pages; i++) { | 1331 | for (i = 0; i < pcpu4k_unit_pages; i++) { |
1325 | void *ptr; | 1332 | void *ptr; |
1326 | 1333 | ||
1327 | ptr = alloc_fn(cpu, PAGE_SIZE); | 1334 | ptr = alloc_fn(cpu, PAGE_SIZE); |
@@ -1330,18 +1337,48 @@ ssize_t __init pcpu_4k_first_chunk(size_t static_size, size_t reserved_size, | |||
1330 | "4k page for cpu%u\n", cpu); | 1337 | "4k page for cpu%u\n", cpu); |
1331 | goto enomem; | 1338 | goto enomem; |
1332 | } | 1339 | } |
1333 | |||
1334 | memcpy(ptr, __per_cpu_load + i * PAGE_SIZE, PAGE_SIZE); | ||
1335 | pcpu4k_pages[j++] = virt_to_page(ptr); | 1340 | pcpu4k_pages[j++] = virt_to_page(ptr); |
1336 | } | 1341 | } |
1337 | 1342 | ||
1343 | /* allocate vm area, map the pages and copy static data */ | ||
1344 | vm.flags = VM_ALLOC; | ||
1345 | vm.size = num_possible_cpus() * pcpu4k_unit_pages << PAGE_SHIFT; | ||
1346 | vm_area_register_early(&vm, PAGE_SIZE); | ||
1347 | |||
1348 | for_each_possible_cpu(cpu) { | ||
1349 | unsigned long unit_addr = (unsigned long)vm.addr + | ||
1350 | (cpu * pcpu4k_unit_pages << PAGE_SHIFT); | ||
1351 | |||
1352 | for (i = 0; i < pcpu4k_unit_pages; i++) | ||
1353 | populate_pte_fn(unit_addr + (i << PAGE_SHIFT)); | ||
1354 | |||
1355 | /* pte already populated, the following shouldn't fail */ | ||
1356 | ret = __pcpu_map_pages(unit_addr, | ||
1357 | &pcpu4k_pages[cpu * pcpu4k_unit_pages], | ||
1358 | pcpu4k_unit_pages); | ||
1359 | if (ret < 0) | ||
1360 | panic("failed to map percpu area, err=%zd\n", ret); | ||
1361 | |||
1362 | /* | ||
1363 | * FIXME: Archs with virtual cache should flush local | ||
1364 | * cache for the linear mapping here - something | ||
1365 | * equivalent to flush_cache_vmap() on the local cpu. | ||
1366 | * flush_cache_vmap() can't be used as most supporting | ||
1367 | * data structures are not set up yet. | ||
1368 | */ | ||
1369 | |||
1370 | /* copy static data */ | ||
1371 | memcpy((void *)unit_addr, __per_cpu_load, static_size); | ||
1372 | } | ||
1373 | |||
1338 | /* we're ready, commit */ | 1374 | /* we're ready, commit */ |
1339 | pr_info("PERCPU: Allocated %d 4k pages, static data %zu bytes\n", | 1375 | pr_info("PERCPU: %d 4k pages per cpu, static data %zu bytes\n", |
1340 | pcpu4k_nr_static_pages, static_size); | 1376 | pcpu4k_unit_pages, static_size); |
1341 | 1377 | ||
1342 | ret = pcpu_setup_first_chunk(pcpu4k_get_page, static_size, | 1378 | ret = pcpu_setup_first_chunk(pcpu4k_get_page, static_size, |
1343 | reserved_size, -1, | 1379 | reserved_size, -1, |
1344 | -1, NULL, populate_pte_fn); | 1380 | pcpu4k_unit_pages << PAGE_SHIFT, vm.addr, |
1381 | NULL); | ||
1345 | goto out_free_ar; | 1382 | goto out_free_ar; |
1346 | 1383 | ||
1347 | enomem: | 1384 | enomem: |