Skip to content

Commit a70c691

Browse files
committed
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 <[email protected]> Acked-by: David S. Miller <[email protected]>
1 parent fb59e72 commit a70c691

File tree

2 files changed

+47
-9
lines changed

2 files changed

+47
-9
lines changed

arch/sparc/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ config HAVE_SETUP_PER_CPU_AREA
102102
config NEED_PER_CPU_EMBED_FIRST_CHUNK
103103
def_bool y if SPARC64
104104

105+
config NEED_PER_CPU_PAGE_FIRST_CHUNK
106+
def_bool y if SPARC64
107+
105108
config GENERIC_HARDIRQS_NO__DO_IRQ
106109
bool
107110
def_bool y if SPARC64

arch/sparc/kernel/smp_64.c

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,26 +1420,61 @@ static void __init pcpu_free_bootmem(void *ptr, size_t size)
14201420
free_bootmem(__pa(ptr), size);
14211421
}
14221422

1423-
static int pcpu_cpu_distance(unsigned int from, unsigned int to)
1423+
static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
14241424
{
14251425
if (cpu_to_node(from) == cpu_to_node(to))
14261426
return LOCAL_DISTANCE;
14271427
else
14281428
return REMOTE_DISTANCE;
14291429
}
14301430

1431+
static 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+
14311454
void __init setup_per_cpu_areas(void)
14321455
{
14331456
unsigned long delta;
14341457
unsigned int cpu;
1435-
int rc;
1436-
1437-
rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE,
1438-
PERCPU_DYNAMIC_RESERVE, 4 << 20,
1439-
pcpu_cpu_distance, pcpu_alloc_bootmem,
1440-
pcpu_free_bootmem);
1441-
if (rc)
1442-
panic("failed to initialize first chunk (%d)", rc);
1458+
int rc = -EINVAL;
1459+
1460+
if (pcpu_chosen_fc != PCPU_FC_PAGE) {
1461+
rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE,
1462+
PERCPU_DYNAMIC_RESERVE, 4 << 20,
1463+
pcpu_cpu_distance,
1464+
pcpu_alloc_bootmem,
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);
14431478

14441479
delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
14451480
for_each_possible_cpu(cpu)

0 commit comments

Comments
 (0)