aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/smp_64.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2009-09-24 05:18:55 -0400
committerTejun Heo <tj@kernel.org>2009-09-28 20:17:57 -0400
commita70c691376c7c7f94af41395848066f59501fffd (patch)
tree8fec04ca394fb1023020c85977d149c83e77e295 /arch/sparc/kernel/smp_64.c
parentfb59e72e7e10fd9d31f4e522f1b28254c2cc8a6c (diff)
sparc64: implement page mapping percpu first chunk allocator
Implement page mapping percpu first chunk allocator as a fallback to the embedding allocator. The next patch will make the embedding allocator check distances between units to determine whether it fits within the vmalloc area so that this fallback can be used on such cases. sparc64 currently has relatively small vmalloc area which makes it impossible to create any dynamic chunks on certain configurations leading to percpu allocation failures. This and the next patch should allow those configurations to keep working until proper solution is found. While at it, mark pcpu_cpu_distance() with __init. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel/smp_64.c')
-rw-r--r--arch/sparc/kernel/smp_64.c53
1 files changed, 44 insertions, 9 deletions
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index ff68373ce6d6..aa36223497b9 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -1420,7 +1420,7 @@ static void __init pcpu_free_bootmem(void *ptr, size_t size)
1420 free_bootmem(__pa(ptr), size); 1420 free_bootmem(__pa(ptr), size);
1421} 1421}
1422 1422
1423static int pcpu_cpu_distance(unsigned int from, unsigned int to) 1423static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
1424{ 1424{
1425 if (cpu_to_node(from) == cpu_to_node(to)) 1425 if (cpu_to_node(from) == cpu_to_node(to))
1426 return LOCAL_DISTANCE; 1426 return LOCAL_DISTANCE;
@@ -1428,18 +1428,53 @@ static int pcpu_cpu_distance(unsigned int from, unsigned int to)
1428 return REMOTE_DISTANCE; 1428 return REMOTE_DISTANCE;
1429} 1429}
1430 1430
1431static void __init pcpu_populate_pte(unsigned long addr)
1432{
1433 pgd_t *pgd = pgd_offset_k(addr);
1434 pud_t *pud;
1435 pmd_t *pmd;
1436
1437 pud = pud_offset(pgd, addr);
1438 if (pud_none(*pud)) {
1439 pmd_t *new;
1440
1441 new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
1442 pud_populate(&init_mm, pud, new);
1443 }
1444
1445 pmd = pmd_offset(pud, addr);
1446 if (!pmd_present(*pmd)) {
1447 pte_t *new;
1448
1449 new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
1450 pmd_populate_kernel(&init_mm, pmd, new);
1451 }
1452}
1453
1431void __init setup_per_cpu_areas(void) 1454void __init setup_per_cpu_areas(void)
1432{ 1455{
1433 unsigned long delta; 1456 unsigned long delta;
1434 unsigned int cpu; 1457 unsigned int cpu;
1435 int rc; 1458 int rc = -EINVAL;
1436 1459
1437 rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE, 1460 if (pcpu_chosen_fc != PCPU_FC_PAGE) {
1438 PERCPU_DYNAMIC_RESERVE, 4 << 20, 1461 rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE,
1439 pcpu_cpu_distance, pcpu_alloc_bootmem, 1462 PERCPU_DYNAMIC_RESERVE, 4 << 20,
1440 pcpu_free_bootmem); 1463 pcpu_cpu_distance,
1441 if (rc) 1464 pcpu_alloc_bootmem,
1442 panic("failed to initialize first chunk (%d)", rc); 1465 pcpu_free_bootmem);
1466 if (rc)
1467 pr_warning("PERCPU: %s allocator failed (%d), "
1468 "falling back to page size\n",
1469 pcpu_fc_names[pcpu_chosen_fc], rc);
1470 }
1471 if (rc < 0)
1472 rc = pcpu_page_first_chunk(PERCPU_MODULE_RESERVE,
1473 pcpu_alloc_bootmem,
1474 pcpu_free_bootmem,
1475 pcpu_populate_pte);
1476 if (rc < 0)
1477 panic("cannot initialize percpu area (err=%d)", rc);
1443 1478
1444 delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; 1479 delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
1445 for_each_possible_cpu(cpu) 1480 for_each_possible_cpu(cpu)